IT评测·应用市场-qidao123.com

标题: 【Java】TCP网络编程:从可靠传输到Socket实战 [打印本页]

作者: 立聪堂德州十三局店    时间: 2025-3-21 06:37
标题: 【Java】TCP网络编程:从可靠传输到Socket实战
运动发起人@小虚竹 想对你说:
这是一个以写作博客为目的的创作运动,旨在鼓励大学生博主们挖掘自己的创作潜能,展现自己的写作才气。假如你是一位热爱写作的、想要展现自己创作才气的小伙伴,那么,快来到场吧!我们一起发掘写作的魅力,誊写出属于我们的故事。我们诚挚约请你到场为期14天的创作寻衅赛!
提醒:在发布作品前,请将不须要的内容删除。

    各位看官,大家早安午安晚安呀~~~
  假如您以为这篇文章对您有帮助的话
  接待您一键三连,小编尽全力做到更好
接待您分享给更多人哦


  今天我们来学习【Java】TCP网络编程:从可靠传输到Socket实战
  目录
1.首先我们再说一下TCP和UDP的区别和相同点
2.连接:通信双方都会记录对方的信息
3.主要是两个api ServerSocket和Socket
4.TCP服务端实战代码演示
5.TCP客户端实战代码演示


TCP的socket的api的差别很大,但是和前面的IO有很大的关联
1.首先我们再说一下TCP和UDP的区别和相同点

   1.TCP是有连接的,UDP无连接(这一点可以在代码中体现)
  2.TCP是面向字节流流的,UDP是面向数据报的
  3.TCP是可靠传输的,UDP是不可靠传输的(这一点在代码中体现不出来)
  4.TCP和UDP都是全双工的
  2.连接:通信双方都会记录对方的信息

   UDP:每次发送数据报都要指定对方的地址(UDP没有存储这个信息)
  一张图
  
  TCP:不须要(不过须要内核主动和客户端建连接(TCP的三次握手,后面我会进行解说)这个过程是系统内核主动完成的)
  对于应用步伐来说,客户端是发起“建立连接”
  
  服务器这边:把内核中建立好的连接拿到应用步伐里面()
  这个ServerSocket只负责绑定端口号,然后通过accept方法 把建立好的连接拿过来(但是一瞬间有很多连接的话,就像生产者消费者模型里面只能进行壅闭等待)
  3.主要是两个api ServerSocket和Socket

   ServerSocket是给服务器用的类,使用这个类用来绑定端口号(这个类负责把系统内核里面已经建立好的连接从队列里面拿过来,)
  Socket:既会给服务器使用的类,也会给客户端使用,通过socket这个对象和客户端进行交互
  (这两个类都是用来体现socket文件的,抽象了网卡如许的硬件设备)
  4.TCP服务端实战代码演示

     
  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.io.PrintWriter;
  5. import java.net.ServerSocket;
  6. import java.net.Socket;
  7. import java.util.Scanner;
  8. import java.util.concurrent.Executor;
  9. import java.util.concurrent.ExecutorService;
  10. import java.util.concurrent.Executors;
  11. public class TcpEchoServer {      // 读取用Scanner ,发送用PrintWriter
  12.     //  1.首先serverSocket调用系统API把连接拿过来,然后交给socket
  13.     //  我们就有了socket这个对象,这个时候我们就可以宣布这个客户端成功和我们服务器建立了联系并且我们拿到了
  14.     // 2.然后我们通过字节流把数据从socket抽象的文件里面读取到,用try包起来,用scanner从流里面读取
  15.     // 3. 我们拿到字符串进行响应
  16.     // 4. 把返回的字符串通过字节流(我们的字符串通过字符流转换成字节流)写回去
  17.     // 5. 把信息打印出来
  18.     private ServerSocket serverSocket = null;
  19.     public TcpEchoServer(int serverPort) throws IOException {
  20.         // 利用这个系统API从内核中取到已经建立好的连接
  21.         // 这个和客户端构造的socket完全不一样,客户端的那个是我们已经拿到的连接
  22.         serverSocket = new ServerSocket(serverPort);  // 服务器自己分配端口号,
  23.     }
  24.     public void start() throws IOException {
  25.         System.out.println("服务器启动");
  26.         // 把队列里面建立好的连接拿过来
  27.         while(true){   //  要一直不断地从那个内核里面不断地拿我们已经建立好的连接!!!
  28.             Socket Clientsocket = serverSocket.accept();
  29.            /* //创建一个新的线程把这个请求进行响应
  30.             Thread t = new Thread(() ->{
  31.                 possessCollection(Clientsocket);
  32.             });
  33.             t.start();*/
  34.             // 但是线程池是更好一点点的选择
  35.             ExecutorService service = Executors.newCachedThreadPool();
  36.             service.submit(() ->{
  37.                 possessCollection(Clientsocket);
  38.             });
  39.         }
  40.     }
  41.     public void possessCollection(Socket Clientsocket){   //
  42.         System.out.printf("[%s,%d] 客户端上线\n" , Clientsocket.getInetAddress(),Clientsocket.getPort());
  43.         // 把端口号和IP拿到
  44.         try(        InputStream inputStream = Clientsocket.getInputStream();   //  这里要用 "  ;  "
  45.                     OutputStream outputStream = Clientsocket.getOutputStream()){
  46.             // 客户可能等会还会继续发送请求(我们循环处理)
  47.             Scanner scanner = new Scanner(inputStream);//每一次读一次缓冲区,缓冲区里面的东西就少一次,都被我读出来了嘛
  48.             while(true){
  49.                 if(!scanner.hasNext()){// 用户不再输入的时候,就直接跳出循环!!!,一直等待用户输入
  50.                     System.out.printf("[%s,%d] 客户端下线\n" , Clientsocket.getInetAddress(),Clientsocket.getPort());
  51.                     break;
  52.                 }
  53.                 String request = scanner.next();
  54.                 // 拿到字符串进行响应
  55.                 String response = process(request);// 拿到响应
  56.                 //4. 拿到字符串的响应,然后我们通过字符流转字节流传递出去
  57.                 PrintWriter printWriter = new PrintWriter(outputStream);
  58.                 printWriter.println(response);
  59.                 // 此处的println不是写到控制台了,而是写到outputStream的流对象了,也就是写入到ClientSocket里面了
  60.                 // 自然这个数据也是通过网卡发出去了
  61.                 printWriter.flush();// 再刷新一下缓存,防止没有发出去,
  62.                 // 总结:  发送和接收数据都是通过socket文件的字节流输入输出来实现,用scanner读字节流,用printWriter写字符串
  63.                 // 5.打印一下交互过程
  64.                 System.out.printf("[%s,%d] req=%s resp=%s\n",Clientsocket.getInetAddress(),Clientsocket.getPort(),
  65.                         request,response);
  66.             }
  67.         }catch(IOException e){
  68.             e.printStackTrace();
  69.         }finally{
  70.             try {
  71.                 Clientsocket.close();
  72.             } catch (IOException e) {
  73.                 throw new RuntimeException(e);
  74.             }
  75.         }
  76.     }
  77.     private String process(String request) {  // 回显服务器
  78.         return request;
  79.     }
  80.     public static void main(String[] args) throws IOException {
  81.         TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
  82.         tcpEchoServer.start();
  83.     }
  84. }
复制代码
   但是这里面会出现两个问题
问题一:为什么我们的ServerSocket对象没有进行close操纵,但是Socket对象却须要close操纵呢?如许不会出现文件资源泄漏吗?
   首先我们须要知道什么时间回造成文件资源泄漏?
  一直频繁申请但是一直不开释就会(什么文件的表项啥的)
  但是ServerSocket对象重新到尾只创建过一次对象,而且一直在把内核中建立的连接拿到。所以说ServerSocket这个对象的生命周期是是陪同着进程消失的(因此不须要特地的进行接纳,等到进程表明JVM会把这个进程里面的东西一起接纳了)
  但是?
  问题二:等待我们写完客户端的代码之后进行讲述
假如启动多个客户端和服务器进行连接(就不行了,这个服务器一直在等待客户端进行输入,我们就须要多个线程并发拿到这个连接)
但是频繁地创建和销毁线程也会有很大开销,线程池是更好一点点选择
5.TCP客户端实战代码演示

     
  1. import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.Socket;
  7. import java.util.Scanner;
  8. public class TcpEchoClient {
  9.     /**
  10.      * 1.随机分配一个端口的发出信息(我们要把服务器的IP地址和端口号给搞进去)
  11.      * 2.我们循环输入一个字符串,把这个字符串用字符流转换成字节流写到socket抽象的文件里面
  12.      * 3.然后我们接收响应(不像服务器,我们又不需要进行处理)
  13.      * 4.我们直接通过Scanner把字节流里面的内容读出来就好了
  14.      */
  15.     private Socket socket = null;
  16.     public TcpEchoClient(String serverIP,int serverPort) throws IOException {
  17.         socket = new Socket(serverIP,serverPort);
  18.     }
  19.     public void start(){
  20.         System.out.println(" -> ");
  21.         Scanner scanner = new Scanner(System.in);
  22.         try(OutputStream outputStream = socket.getOutputStream();
  23.             InputStream inputStream = socket.getInputStream()){
  24.             while(true){
  25.                /* if(!scanner.hasNext()){  // 用户不想输入了,就直接退出了
  26.                     break;   不需要这个
  27.                 }*/
  28.                 //     * 2.我们循环输入一个字符串,把这个字符串用字符流转换成字节流写到socket抽象的文件里面
  29.                 String request = scanner.next();
  30.                 PrintWriter printWriter = new PrintWriter(outputStream);  // 这些流尽量都放到try()里面
  31.                 printWriter.println(request);
  32.                 printWriter.flush();// 一定不要忘记刷新缓存区'
  33.                 //      * 4.我们直接通过Scanner把字节流里面的内容读出来就好了
  34.                 Scanner scannerNetwork = new Scanner(inputStream); // 这个Scanner尽量也是放到try()里面
  35.                 String response = scannerNetwork.next();
  36.                 System.out.println(response);
  37.             }
  38.         }catch(IOException e){
  39.             e.printStackTrace();
  40.         }
  41.     }
  42.     public static void main(String[] args) throws IOException {
  43.         TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1",9090);
  44.         tcpEchoClient.start();
  45.     }
  46. }
复制代码
     上述就是【Java】TCp网络编程:TCP网络编程:从可靠传输到Socket实战的全部内容啦
  能看到这里相信您一定对小编的文章有了一定的认可。
  有什么问题接待各位大佬指出
接待各位大佬评论区留言修正~~

您的支持就是我最大的动力​​​!!!

  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4