网络编程-06丨传统Socket网络编程

Posted by jiefang on March 10, 2021

传统Socket网络编程

Server端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class SocketServer {

   public static void main(String[] args) throws Exception {
      ServerSocket serverSocket = new ServerSocket(9000);
      while(true) {
         Socket socket = serverSocket.accept(); // 在这里会阻塞住,一直等待别人跟建立连接
         new Worker(socket).start();
      }
      
      // 如果有一个客户端跟他发起了TCP三次握手,尝试建立一个连接
      // 这里就会构建出来一个Socket,这个Socket就代表了跟某个客户端的一个TCP连接,Socket连接
      
      // 如果有人要跟你建立TCP连接,接下来基于TCP协议来传输数据,发送一个一个的TCP包过来
      // 此时他会必须是跟你的某个服务器程序的端口号建立的连接
      // 客户端跟你的ServerSocket之间,互相传递3次握手的TCP包,连接就建立,互相交换了一些数据
   }
   
   static class Worker extends Thread {
      
      Socket socket;
      
      public Worker(Socket socket) {
         this.socket = socket;
      }
      
      @Override
      public void run() {
         try {
            // 接下来,一旦建立了TCP连接之后
            // 客户端就会通过IO流的方式发送数据过来,无限的流
            // 所以说底层的TCP协议会把流式的数据拆分为一个一个的TCP包,包裹在IP包里,以太网包
            // 最后通过底层的网络硬件设备以及以太网的协议,发送数据给你发送过来
            InputStreamReader in = new InputStreamReader(socket.getInputStream());
            OutputStream out = socket.getOutputStream();
            
            char[] buf = new char[1024 * 1024];
            int len = in.read(buf);// read会有一个阻塞的效果,他会阻塞在这里尝试读取数据出来
            
            // Socket的输入流,相当于就是不停的读取人家通过TCP协议发送过的一个一个的TCP包
            // 把TCP包的数据通过IO输入流的方式提供给你
            // 你就可以通过IO输入流读取的方式把TCP包的数据读出来放入JVM内存的一个缓冲数组中
            while(len != -1) {
               String request = new String(buf, 0, len);
               System.out.println("[" + Thread.currentThread().getName() 
                     + "]服务端接收到了请求:" + request);
               out.write("收到,收到".getBytes());  
               
               len = in.read(buf);
               
               // 你需要反复的去读取socket流传输过来的数据
               // 因为人家是不停的用流的方式发送数据过来的,你不需要不停的读取
               // buf才1kb,可能你才读取了1kb的数据
               // 后面可能还跟了几百kb的数据,所以需要你不停的读取
               
               // 他的意思就是说,你通过IO流发送响应数据回去
               // 此时在底层会把你的响应数据拆分为一个一个的TCP包,回传回去
               // 客户端就可以接受到你发送的TCP包
            }
            out.close();
            in.close();
            socket.close(); // 走TCP四次挥手连接就直接断开了
         } catch (Exception e) {
            e.printStackTrace();  
         }
      }
   }
}

Client端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class SocketClient {
   public static void main(String[] args) throws Exception {
      for(int i = 0; i < 10; i++) {
         new Thread() {
            
            public void run() {
               try {
                  Socket socket = new Socket("localhost", 9000);
                  
                  // 此处应该是会找DNS服务查找域名对应的IP地址
                  // 接下来需要跟那个ip地址上的9000端口的服务器程序进行TCP三次握手,建立连接
                  // 这个时候他就会构造一个三次握手中的第一次握手的TCP包
                  // 在这个TCP包里放入三次握手需要的数据
                  // 把这个TCP包封装在IP包里,是有对应的目标的IP地址,再封装在以太网包里
                  // 通过底层的硬件设备走以太网协议出去,路由器,人家通过IP地址查找路由表,确定下一个路由器的位置
                  // 查找下一个路由器的mac地址写入到以太网包头,走下一个子网广播出去
                  // 通过这种方式层层转发,一直到对应的服务器上去
                  
                  // 服务器接收到三次握手的第一次握手的TCP包
                  // 就会回传第二次握手的TCP包给这个客户端的程序,客户端再次发送第三次握手的TCP包过去
                  // 三次握手成功,TCP连接建立起来了
                  
                  InputStreamReader in = new InputStreamReader(socket.getInputStream());
                  OutputStream out = socket.getOutputStream();
                  char[] buf = new char[1024 * 1024];
                  
                  while(true) {
                     try {
                        out.write("你好".getBytes()); // 发送数据流,底层拆分为一个一个的TCP包发过去
                        int len = in.read(buf);
                        
                        if(len != -1) {
                           String response = new String(buf, 0, len);
                           System.out.println("[" + Thread.currentThread().getName() 
                                 + "]客户端接收到了响应:" + response);
                        }
                        
                        Thread.sleep(1000);  
                     } catch(Exception e) {
                        e.printStackTrace(); 
                        in.close();
                        out.close();
                        socket.close(); // 其实就会走TCP四次挥手断开连接
                     }
                  }
               } catch (Exception e) {
                  e.printStackTrace();  
               }
            };
         }.start();
      }
   }
}