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指定。 且参数port指定服务器要绑定的端口(注意客户端的端口由操作系统随机分配),即服务器要监听的端口;参数backlog指定客户连接请求队列中的长度; 参数bindAddr指定服务器要绑定的IP地址。 |
当队列中的连接请求达到了队列的最大容量时,服务器进程所在的主机会拒绝新的连接请求。只有当服务器进程通过ServerSocket的accept()方法从队列中取出连接请求,使队列腾出空位时,队列才能继续加入新的连接请求。
而对于客户进程,如果它发出的连接请求被加入到服务器的队列中,就意味着与服务器的连接建立成功。客户进程从Socket构造方法中正常返回。
// 客户进程尝试与建立与服务进程间的30次连接
public class BacklogClient {
public static void main(String[] args) throws Exception {
final int linknum = 30;
String host = "localhost";
int port = 7777;
Socket [] sockets = new Socket[linknum];
for( int i=0;i<linknum;i++){
sockets[i] = new Socket( host, port );
System.out.println("第 "+(i+1)+" 次连接成功");
}
Thread.sleep( 1000*3 );
for( int i=0;i<linknum;i++ ){
sockets[i].close(); //断开连接.
}
}
}
//服务进程:
public class BacklogServer {
private int port = 7777;
private ServerSocket server;
private int linknum = 5;
public BacklogServer() throws IOException{
server = new ServerSocket( port, linknum); // 连接请求队列的最大长度为linknum.
System.out.println("服务器已启动...");
}
public void service(){
while(true){
Socket socket = null;
try {
socket = server.accept(); // 从连接请求队列中取出一个连接请求.
System.out.println(" 新的客户端 已连接 : " + socket.getInetAddress() + " : " + socket.getPort() );
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if( socket != null ){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
BacklogServer bs = new BacklogServer();
//Thread.sleep( 1000*60*5 );
bs.service();
}
}
另外注意的是,在某些情况下仍会采用操作系统限定的队列的最大长度:
1. backlog 参数的值大于操作系统限定的队列的最大长度。
2. backlog参数的值小于或等于0;
3. 在ServerSocket构造方法中没有设置backlog参数。
3.设定绑定的IP地址:
ServerSocket server = new ServerSocket(7777,10,InetAddress.getByName("192.168.14.253"));
//InetAddress.getByName("192.168.14.253") 返回的是代表 192.168.14.253的IP地址。
4.默认构造方法的作用,即不带参数的构造方法:
ServerSocket server = new ServerSocket();
server.setReuseAddress(true); // (1). 设置ServerSocket的选项,
server.bind( new InetSocketAddress(7777) ); // (2).与7777端口绑定
// 但是如果 (1) 与 (2) 对换,那么server.setReuseAddress(true) 就不起任何作用,因为SO_REUSEADDR选项必须在服务器绑定端口之前设置。
5.关闭ServerSocket:
isClosed() 方法判断ServerSocket是否关闭,只有执行了ServerSocket的close()方法,其才返回true,否则即使ServerSocket还没有和特定端口绑定,该方法也返回false;
isBound()方法判断ServerSocket是否已经与一个端口绑定,只要ServerSocket已经与一个端口绑定,即使她已经被关闭,该方法也会返回true;
而如果要确定一个ServerSocket已经与特定端口绑定,并且还没有被关闭:
boolean isOpen = serverSocket.isBound() && !serverSocket.isClosed();
6.设定连接时间,延迟和带宽的相对重要性:
Socket类与ServerSocket类都提供了一个 socket.setPerformancePreferences( ) 方法。
public void setPerformancePreferences( int connectionTime, int latency, int bandwidth)
// 参数connectionTime : 表示用最少时间建立连接。
// 参数latency : 表示最小延迟
// 参数bandwidth : 表示最高带宽。
// 假设:setPerformancePreferences( 2,1,3 );
//则其表示最高带宽最重要,其次是最少连接时间,最后是最小延迟。