Java套接字编程之TCP编程(2)

如果主机只有一个IP地址,那么默认情况下,服务器程序就与该IP地址绑定。ServerSocket的第4个构造方法ServerSocket(int port, int backlog, InetAddress bindAddr)有一个bindAddr参数,它显式指定服务器要绑定的IP地址,该构造方法适用于具有多个IP地址的主机。假定一个主机有两个网卡,一个网卡用于连接到Internet, IP地址为222.67.5.94,还有一个网卡用于连接到本地局域网,IP地址为192.168.3.4。如果服务器仅仅被本地局域网中的客户访问,那么可以按如下方式创建ServerSocket:
ServerSocket serverSocket = new ServerSocket(80,10,InetAddress.getByName ("192.168.3.4"));

2.1.4 默认构造方法的作用

ServerSocket有一个不带参数的默认构造方法。通过该方法创建的ServerSocket不与任何端口绑定,接下来还需要通过bind()方法与特定端口绑定。

这个默认构造方法的用途是,允许服务器在绑定到特定端口之前,先设置ServerSocket的一些选项。因为一旦服务器与特定端口绑定,有些选项就不能再改变了。

在以下代码中,先把ServerSocket的SO_REUSEADDR选项设为true,然后再把它与8000端口绑定:

ServerSocket serverSocket=new ServerSocket(); serverSocket.setReuseAddress(true); //设置ServerSocket的选项 serverSocket.bind(new InetSocketAddress(8000)); //与8000端口绑定

如果把以上程序代码改为:

ServerSocket serverSocket=new ServerSocket(8000); serverSocket.setReuseAddress(true); //设置ServerSocket的选项

那么serverSocket.setReuseAddress(true)方法就不起任何作用了,因为SO_ REUSEADDR选项必须在服务器绑定端口之前设置才有效。

2.2 接收和关闭与客户的连接

ServerSocket的accept()方法从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的Socket对象,并将它返回。如果队列中没有连接请求,accept()方法就会一直等待,直到接收到了连接请求才返回。

接下来,服务器从Socket对象中获得输入流和输出流,就能与客户交换数据。当服务器正在进行发送数据的操作时,如果客户端断开了连接,那么服务器端会抛出一个IOException的子类SocketException异常:
java.net.SocketException: Connection reset by peer
这只是服务器与单个客户通信中出现的异常,这种异常应该被捕获,使得服务器能继续与其他客户通信。

2.3 关闭ServerSocket

ServerSocket的close()方法是服务器释放占用的端口,并且断开与所有客户端的连接。当一个服务器程序运行结束时,即使没有执行ServerSocket的close()方法,操作系统也会释放这个服务器占用的端口。因此,服务器程序并不一定要在结束之前执行ServerSocket的close方法。

在某些情况下,如果希望及时释放服务器的端口,以便让其他程序占用这个端口,则可以显式调用close()方法。例如以下代码用于扫描1~65535之间的端口号。如果ServerSocket成功创建,意味着该端口未被其他服务器进程绑定,否者说明该端口已经被其他进程占用:

for(int i = 1; i < 65535; i++){ try{ ServerSocket serverSocket = new ServerSocket(i); serverSocket.close(); }catch(Exception e){ System.out.println("端口" + i + "已经被其他服务器进程占用"); } }

以上程序代码创建了一个ServerSocket对象后,就马上关闭它,以便及时释放它占用的端口,从而避免程序临时占用系统的大多数端口。

ServerSocket的isClose()方法判断ServerSocket是否关闭,只有执行了ServerSocket的close()方法,isClose()方法的返回值为true,即使ServerSocket还没有和特定的端口绑定,isClose()方法的返回值也是false。

ServerSocket的isBound()方法判断ServerSocket是否已经与一个端口绑定,只要ServerSocket已经与一个端口绑定,即使它已经被关闭,isBound()方法也会返回true。

如果要确定一个ServerSocket已经与特定端口绑定,并且还没有被关闭,则可以采用以下方式:
boolean isOpen = serverSocket.isBound() && !serverSocket.isClosed();

2.4 获取ServerSocket的信息

ServerSocket的以下两个get方法可分别获得服务器绑定的IP地址,以及绑定的端口:

public InetAddress getInetAddress();

public int getLocalPort()

前面已经讲到,在构造ServerSocket时,如果把端口设为0,那么将由操作系统为服务器分配一个端口(称为匿名端口),程序只要调用getLocalPort()方法就能获知这个端口号。如例程3-3所示的RandomPort创建了一个ServerSocket,它使用的就��匿名端口。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/465966d9ed8859b6ae878cfdb1cfa975.html