[Java] socket 简介

一、简介

内容来自: What Is a Socket?

Socket 是网络上两个程序间双向交流连接的一个端点(类似于打电话时的两台手机 Java Socket对象原理的详细介绍),基于TCP/IP协议,稳定有序。

Definition:
A socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to.

An endpoint is a combination of an IP address and a port number. Every TCP connection can be uniquely identified by its two endpoints. That way you can have multiple connections between your host and the server.

socket 连接示意图:

连接示意图

工作模式:

This client program is straightforward and simple because the echo server implements a simple protocol. The client sends text to the server, and the server echoes it back. When your client programs are talking to a more complicated server such as an HTTP server, your client program will also be more complicated. However, the basics are much the same as they are in this program:

    • Open a socket.
    • Open an input stream and output stream to the socket.
    • Read from and write to the stream according to the server's protocol.
    • Close the streams.
    • Close the socket. Only step 3 differs from client to client, depending on the server. The other steps remain largely the same.
    • socket 工作模式总结如下:

      1. server 端监听一个本地端口,client 端通过IP地址、端口号(endpoint)发起连接请求,客户端同时会提供自身的端口号给服务端以互相通信(通常由系统指定);
      2. 一旦连接建立,accept() 方法会返回一个新的 socket 对象代表客户端,server 端则继续监听相同的本地端口号等待客户端连接;
      3. 客户端和服务端基于数据流读/写数据;
      4. 关闭流;
      5. 关闭socket。

      其中,server 端和 client 端建立连接官方文档说明如下: Writing the Server Side of a Socket

      If the server successfully binds to its port, then the ServerSocket object is successfully created and the server continues to the next step—accepting a connection from a client (the next statement in the try-with-resources statement):

      clientSocket = serverSocket.accept();

      The accept method waits until a client starts up and requests a connection on the host and port of this server. (Let’s assume that you ran the server program KnockKnockServer on the computer named knockknockserver.example.com.) In this example, the server is running on the port number specified by the first command-line argument. When a connection is requested and successfully established, the accept method returns a new Socket object which is bound to the same local port and has its remote address and remote port set to that of the client. The server can communicate with the client over this new Socket and continue to listen for client connection requests on the original ServerSocket .This particular version of the program doesn’t listen for more client connection requests. However, a modified version of the program is provided in Supporting Multiple Clients.

      二、代码示例

      代码来自:Reading from and Writing to a Socket

      Socket 服务端代码:

      package com.kascend.test.socket;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      /**
       * Socket 服务端类
       *
       * @author wengliemiao
       */
      public class EchoServer {
      
          public static void main(String[] args) {
              int portNumber = 8080;
              try (
                      ServerSocket serverSocket =
                              new ServerSocket(portNumber);
                      Socket clientSocket = serverSocket.accept();
                      PrintWriter out =
                              new PrintWriter(clientSocket.getOutputStream(), true);
                      BufferedReader in = new BufferedReader(
                              new InputStreamReader(clientSocket.getInputStream()));
              ) {
                  String inputLine;
                  while ((inputLine = in.readLine()) != null) {
                      System.out.println(inputLine);
                      out.println("from server: " + inputLine);
                  }
              } catch (IOException e) {
                  System.out.println("Exception caught when trying to listen on port "
                          + portNumber + " or listening for a connection");
                  System.out.println(e.getMessage());
              }
          }
      }
      
      

      Socket 客户端:

      package com.kascend.test.socket;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.Socket;
      import java.net.UnknownHostException;
      
      /**
       * Socket 客户端类
       *
       * @author wengliemiao
       */
      public class EchoClient {
      
          public static void main(String[] args) {
              String hostName = "127.0.0.1";
              int portNumber = 8080;
      
              try (
                      Socket echoSocket = new Socket(hostName, portNumber);
                      PrintWriter out =
                              new PrintWriter(echoSocket.getOutputStream(), true);
                      BufferedReader in =
                              new BufferedReader(
                                      new InputStreamReader(echoSocket.getInputStream()));
                      BufferedReader stdIn =
                              new BufferedReader(
                                      new InputStreamReader(System.in))
              ) {
                  String userInput;
                  while ((userInput = stdIn.readLine()) != null) {
                      out.println(userInput);
                      System.out.println("echo: " + in.readLine());
                  }
              } catch (UnknownHostException e) {
                  System.err.println("Don't know about host " + hostName);
                  System.exit(1);
              } catch (IOException e) {
                  System.err.println("Couldn't get I/O for the connection to " +
                          hostName);
                  System.exit(1);
              }
          }
      }
      
      

      先运行服务端类,再运行客户端类。

      在客户端控制台输入:

      Hello, I'm wlmmm.
      666666
      

      服务端控制台输出为:
      服务端控制台输出

      客户端控制台输出为:
      客户端控制台输出

      注意: Socket clientSocket = serverSocket.accept(); 这行代码会阻塞直到有客户端连接建立。

      accept方法

      三、多线程处理

      官方文档来源:Writing the Server Side of a Socket

      To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads—one thread per each client connection.

      The basic flow of logic in such a server is this:

      while (true) {
      accept a connection;
      create a thread to deal with the client;
      }

      The thread reads from and writes to the client connection as necessary.

      多线程实现方式如下:

      package com.wlm.socket;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      /**
       * 服务端 socket 多线程方式
       *
       * @author wengliemiao
       */
      public class EchoServerMultiThread {
      
          public static void main(String[] args) {
              int portNumber = 8080;
              try {
                  ServerSocket serverSocket = new ServerSocket(portNumber);
                  while (true) {
                      new Thread(new ServerThread(serverSocket.accept())).start();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          private static class ServerThread implements Runnable {
      
              Socket socket = null;
      
              public ServerThread(Socket socket) {
                  this.socket = socket;
              }
      
              @Override
              public void run() {
                  try {
                      PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                      String inputLine;
                      while ((inputLine = in.readLine()) != null) {
                          System.out.println(inputLine);
                          out.println("from server: " + inputLine);
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
      

      启动EchoServerMultiThread,建立两个 socket 客户端 EchoClient, EchoClient2 (实现和前面一致),同时向 server 端 socket 输入数据,结果为:
      client1

      client2

      serverMultiThread

    • 1
      点赞
    • 3
      收藏
      觉得还不错? 一键收藏
    • 1
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论 1
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值