# 简介

该部分之所以为 0,是因为在之后 NIOAIO 的学习都会大量用到 Socket 的知识,所以为了更好的让读者阅读下去,这里开始对 Socket 做出一点补充。

客户端与服务器连接之后,通过对 Socket 对象的写入和读取进行通信。

连接过程:

  • 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
  • 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
  • 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
  • Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
  • 在服务器端, accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket

TCP 是双向通信协议,服务器和客户端可以同时互相发消息。客户端的 Socket 的输出流就是服务端的输入流,客户端的输入流就是服务端的输出流

# 相关实现类

# ServerSocket 类

服务器应用程序通过该类获取端口(构造函数传入端口),并且监听客户端请求。

构造方法

// 其他三个构造方法,从右至左依次减少一个参数
// 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
public ServerSocket(int port, int backlog, InetAddress address) throws IOException

相关方法

// 获取该 Socket 监听的端口
public int getLocalPort()
    
// 侦听并接受到此套接字的连接
public Socket accpet() throws IOException
    
// 将 ServerSocket 绑定到特定地址 (IP 地址和端口号)
public void bind(SocketAddress host,int backlog)

# Socket 类

客户端和服务端通信使用的套接字,客户端要获取一个 Socket 直接实例化,服务端通过 accept 方法返回值。

// 连接到指定主机的指定端口号上
public Socket(String host, int port) 
    
// 连接到指定 IP 地址的指定端口号
public Socket(InetAddress host, int port)

Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。

// 将此套接字连接到服务器,并指定一个超时值。
public void connect(SocketAddress host, int timeout) throws IOException
// 返回套接字连接的地址。
public InetAddress getInetAddress()
    
// 返回套接字连接的远程端口,本地端口是 getLocalPort
public int getPort()
    
// 获取输入 / 输出流
public OutputStream getOutpurStream();

# InetAddress 类

该类表示互联网协议(IP),该类的核心方法,直接在 IDE 里面打出 get 即可。

# 示例

客户端代码

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8888);
        // 输出流,发送数据给服务端
        OutputStream out = socket.getOutputStream();
        String s = "hello world";
        out.write(s.getBytes());
        
        // 其实也可以是输入流,无非就是接收来自服务器的数据
        out.close();
    }
}

服务端代码

public class Server {
    public static void main(String[] args) throws IOException {
        
        ServerSocket serverSocket = new ServerSocket(8888);
        
        Socket socket = serverSocket.accept();
        InputStream in = socket.getInputStream();
        byte[] arr = new byte[20];
        
        // 也可以用其他借助装饰者类实现更多功能的类
        in.read(arr);
        server.close();
    }
}

其实服务端应该是 while 循环不断获取客户端传过来的连接。我们看到客户端和服务端可以传输数据,这也是 IO 流,比如服务端要获取客户端传过来的数据,就需要调用 read 方法,如果客户端那边数据没准备好,就会一直阻塞在这里。

客户端是一样的道理。既然存在阻塞,那么在设计的时候就存在同步异步问题,也就是之后涉及的 NIO,AIO 等知识。

# 参考

菜鸟教程:https://www.runoob.com/java/java-networking.html