对于接受连接的服务器,Java提供了一个ServerSocket表示服务器Socket。从技术上讲,服务器socket在服务器上运行,监听入站TCP连接。每个服务器Socket监听服务器机器上的一个特定端口。服务器Socket等待连接,客户端Socket发起连接。一旦ServerSocket建立了连接,服务器会使用一个常规的Socket对象向客户端发送数据,数据总是通过常规Socket传输。

ServerSocket

构造函数

public ServerSocket() throws IOException
public ServerSocket(int port) throws IOException
public ServerSocket(int port, int backlog) throws IOException
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

注意事项:

  1. port:服务器要监听的端口;backlog:客户端连接请求的队列长度;bindAddr:服务器绑定IP。
  2. 如果端口被占用或者没有权限使用某些端口会抛出BindException错误。例如1~1023的端口需要管理员才拥有权限绑定。
  3. 如果设置端口为0,则系统会自动为其分配一个端口;
  4. bindAddr用于绑定服务器IP,之所以这样设置,是因为有些机器可能有多个网卡。
  5. ServerSocket一旦绑定了监听端口,就无法更改。ServerSocket()可以实现在绑定端口前设置其他的参数。

接受连接

ServerSocket server = new ServerSocket(10000);  // 创建一个监听端口10000的服务器Socket
Socket connection = server.accept();    // 接受一个连接

accept()调用会阻塞,如果服务器面向多个客户的连接:

  1. 必须使用while循环,每次循环阻塞在accept(),等待新的连接到来,这样才能返回新的socket。如果不使用while死循环每次阻塞在accept(),也可以面向多个客户端连接,此时将在socket抽象层,自动建立socket,并且该socket不受控制。
  2. 必须使用数组(或其他数据结构)保存当前accept创建的socket,否则下次新的socket建立后,当前的socket将不受控制。
while (true) {
    Socket connection = server.accept();
}

绑定
使用无参数的构造函数后,可以将其绑定到一个端口。

public void bind(SocketAddress bindpoint) throws IOException

将套接字绑定到本地地址。如果地址为 null,则系统将挑选一个临时端口和一个有效本地地址来绑定套接字(源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字)。

关闭

public void close() throws IOException

关闭此套接字。结束处理时一定要关闭Socket,不能依赖客户端来结束。使用完ServerSocket也应当将其关闭。套接字被关闭后,便不可在以后的网络连接中使用(即无法重新连接或重新绑定)。需要创建新的套接字。关闭此套接字也将会关闭该套接字的 InputStream 和 OutputStream。如果此套接字有一个与之关联的通道,则关闭该通道。

ServerSocket选项

SO_TIMEOUT
表示等待入站连接的时间,以毫秒计。

public void setSoTimeout(int timeout) throws SocketException
public int getSoTimeout() throws IOException

SO_REUSEADDR
服务器的SO_REUSEADDR确定了是否允许一个新的Socket绑定到之前使用过的一个端口,而此时可能还有一些发送到原Socket的数据正在网络上传输,有两个方法分别获取和设置这个选项:

public boolean getReuseAddress() throws SocketException
public void setReuseAddress(boolean on) throws SocketException

SO_RCVBUF
设置服务器Socket接受客户端Socket默认接收缓冲区大小。

public int getReceiveBufferSize() throws SocketException
public void setReceiveBufferSize(int size) throws SocketException