构造 ServerSocket
ServerSocket 的构造方法有以下几种重载形式- ServerSocket() throws IOException
- ServerSocket(int port) throws IOException
- ServerSocket(int port, int backlog) throws IOException
- ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
复制代码 参数 port 指定服务器要绑定的端口(即服务器要监听的端口),参数 backlog 指定客户连接请求队列的长度,参数 bindAddr 指定服务器要绑定的 IP 地址
1. 绑定端口
除了第 1 个不带参数的构造方法,其他构造方法都会使服务器与特定端口绑定,由参数 port 指定,无法绑定则抛出 IOException,一般是因为端口已经被其他服务占用,或者没有足够的权限去绑定
如果把参数 port 设为 0,则表示由操作系统为服务器分配一个任意的可用端口,也被称为匿名端口。对于多数服务器,会使用明确的端口,而不会使用匿名端口,因为客户程序需要事先知道服务器的端口,才能方便地访问服务器- ServerSocket(int port) throws IOException
复制代码 2. 设定客户连接请求队列的长度
当服务器进程运行时,可能会同时监听到多个客户的连接请求,管理客户连接请求的任务是由操作系统来完成的。操作系统把这些连接请求存储在一个先进先出的队列中,许多操作系统都限定了队列的最大长度,一般为 50。当队列中的连接请求达到了队列的最大长度时,服务器进程所在的主机会拒绝新的连接请求,只有当服务器进程通过 ServerSocket 的 accept() 方法从队列中取出连接请求,使队列腾出空位,队列才能继续加入新的连接请求
ServerSocket 构造方法的 backlog 参数用来显式设置连接请求队列的长度,它将覆盖操作系统限定的队列的最大长度。值得注意的是,在以下几种情况中,仍然会采用操作系统限定的队列的最大长度:
- backlog 参数的值大于操作系统限定的队列的最大长度
- backlog 参数的值小于或等于 0
- 在 ServerSocket 构造方法中没有设置 backlog 参数
3. 设定绑定的 IP 地址
ServerSocket 的第 4 个构造方法有个 bindAddr 参数,它显式地指定服务器要绑定的 IP 地址,适用于具有多个 IP 地址的主机
接收和关闭与客户的连接
ServerSocket 的 accept() 方法从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的 Socket 对象,井将它返回。如果队列中没有连接请求,accept() 方法就会一直等待下去。接下来,服务器从 Socket 对象获得输入流和输出流,就能与客户交换数据了
以下代码展示了单线程服务器采用的通信流程- public void service() {
- while (true) {
- Socket socket = null;
- try {
- // 从连接请求队列中取出一个连接
- socket = serverSocket.accept();
- System.out.printin("New connection accepted " + socket,getInetAddress() + ":" + socket.getPort());
- //接收和发送数据
- ...
- } catch (IOException e) {
- // 这只是与单个客户通信时遇到的异常,可能是由于客户端过早断开连接引起的
- // 这种异常不应该中断整个while循环
- e.printStackTrace();
- } finally {
- try {
- // 与一个客户通信结束后,要关闭Socket
- if(socket != null) socket.close();
- }catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
复制代码 关闭 ServerSocket
ServerSocket 的 close() 方法使服务器释放占用的端口,并且断开与所有客户的连接
ServerSocket 的 isClosed() 方法判断 ServerSocket 是否关闭,只有执行了 ServerSocket 的 close() 方法,isClosed() 方法才返回 true,否则即使 ServerSocket 还有没有和特定端口绑定,该方法也会返回 false
ServerSocker 的 isBound() 方法判断 ServerSocket 是否已经与一个端口绑定,只要 ServerSocket 已经与一个端口绑定,即使它已经被关闭,该方法也会返回 true
如果需要判断一个 ServerSocket 是否已经与特定端口绑定,并且还没有被关闭,则可以采用以下方式- boolean isOpen = serverSocket.isBound() && !serverSocket.isClosed();
复制代码 获取 ServerSocket 的信息
ServerSocket 的以下两个 get 方法分别用于获得服务器绑定的 IP 地址,以及绑定的端口- public InetAddress getInetAddress()
- publlc int getLocalPort()
复制代码 ServerSocket 选项
1. SO_TIMEOUT
表示 ServerSocket 的 accept() 方法等待客户连接的超时时间,以 ms 为单位。如果 SO_TIMEOUT 的值为 0 则表示永远不会超时,这是 SO_TIMEOUT 的默认值- public void setSoTimeout(int timeout) throws SocketException
- public int getSoTimeout() throws IOException
复制代码 2. SO_REUSEADDR
这个选项与 Socket 的 SO_REUSEADDR 选项相同,决定如果网络上仍然有数据向旧的 ServerSocket 传输,那么是否允许新的 ServerSocket 绑定到与旧的 ServerSocket 同样的端口- public void setResuseAddress(boolean on) throws SocketException
- public boolean getResuseAddress() throws SocketException
复制代码 3. SO_RCVBUF
表示服务器端的用于接收数据的缓冲区的大小,以字节为单位- public void setReceiveBufferSize(int size) throws SocketException
- public int getReceiveBufferSize() throws SocketException
复制代码 4. 设定连接时间、延迟和带宽的相对重要性
该方法的作用与 Socket 的 setPerformancePreferences() 方法的作用相同
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |