服务器运行的时候可以监听多个客户端的连接请求。管理客户连接请求的任务是由操作系统来完成的。操作系统把这些连接请求存储在一个先进先出的队列中。许多操作系统限定了队列的最大长度,一般为50。当队列中的连接请求达到了队列的最大容量时,服务器进程所在的主机会拒绝新的连接请求。只有当服务器进程通过ServerSocket 的accept()方法从队列中取出连接请求,使队列腾出空位时,队列才能继
续加入新的连接请求。
如果客户进程发出的连接请求被服务器拒绝,Socket 构造方法就会抛出
ConnectionException。
例如:如下测试代码
运行以上测试程序,执行结果为:
第1 次连接成功
第2 次连接成功
第3 次连接成功
Exception in thread "main" java.net.ConnectException: Connection refused: connect.....................
如果在测试方法代码最后加上一句server.service();运行结果为
第1 次连接成功
第2 次连接成功
第3 次连接成功
…
第100 次连接成功 ,可以看到100次连接可以成功获得建立
[b]绑定IP地址:[/b]
如果主机只有一个IP 地址,那么默认情况下,服务器程序就与该IP 地址绑定。ServerSocket
构造方法ServerSocket(int port, int backlog, InetAddress bindAddr)有一个bindAddr 参数,它显式指定服务器要绑定的IP 地址,该构造方法适用于具有多个IP 地址的主机。假定一个主机有两个网卡,一个网卡用于连接到Internet, IP 地址为222.67.5.94,还有一个连接到本地局域网,IP 地址为192.168.3.4。如果服务器仅仅被本地局域网中的客户访问,那么可以按如下方式创建ServerSocket:
[b]默认构造:[/b]
ServerSocket 有一个不带参数的默认构造方法。通过该方法创建的
ServerSocket 不与任何端口绑定,接下来还需要通过bind()方法与特定端口绑
定。这个默认构造方法的用途是,允许服务器在绑定到特定端口之前,先设置
ServerSocket 的一些选项。因为一旦服务器与特定端口绑定,有些选项就不能
再改变了。
这样设置是有效的,但是如果吧第二句和第三句位置互换就失效了。
当服务器正在进行发送数据的操作时,如果客户端断开了连接,那么服务器端会抛出一个IOException的子类SocketException 异常:
java.net.SocketException: Connection reset by peer
这只是服务器与单个客户通信中出现的异常,这种异常应该被捕获,使得服务器能继续与其他客户通信。
ServerSocket 有以下3 个选项。
1.SO_TIMEOUT:表示等待客户连接的超时时间。
2. SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。
3. SO_RCVBUF:表示接收数据的缓冲区的大小。
当服务器执行ServerSocket 的accept()方法时,如果连接请求队列为空,服务
器就会一直等待,直到接收到了客户连接才从accept()方法返回。如果设定了
超时时间,那么当服务器等待的时间超过了超时时间,就会抛出
SocketTimeoutException,它是InterruptedException 的子类。
SO_RCVBUF 表示服务器端的用于接收数据的缓冲区的大小,以字节为单位。一般
说来,传输大的连续的数据块(基于HTTP 或FTP 协议的数据传输)可以使用较
大的缓冲区,这可以减少传输数据的次数,从而提高传输数据的效率。而对于交
互式的通信(Telnet 和网络游戏),则应该采用小的缓冲区,确保能及时把小
批量的数据发送给对方。
续加入新的连接请求。
如果客户进程发出的连接请求被服务器拒绝,Socket 构造方法就会抛出
ConnectionException。
例如:如下测试代码
public class Client {
public static void main(String args[])throws Exception{
final int length=100;
String host="localhost";
int port=8080;
Socket[] sockets=new Socket[length];
for(int i=0;i<length;i++){ //试图建立100 次连接
sockets[i]=new Socket(host, port);
System.out.println("第"+(i+1)+"次连接成功");
}
Thread.sleep(3000);
for(int i=0;i<length;i++){
sockets[i].close(); //断开连接
}
}
}
public class Server {
private int port=8000;
private ServerSocket serverSocket;
public Server() throws IOException {
serverSocket = new ServerSocket(port,3); //连接请求队列的长度为3
System.out.println("服务器启动");
}
while (true) {
Socket socket=null;
try {
socket = serverSocket.accept(); //从连接请求队列中取出一个
连接
System.out.println("New connection accepted " +
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 {
Server server=new Server();
Thread.sleep(60000*10); //睡眠10 分钟
}
}
运行以上测试程序,执行结果为:
第1 次连接成功
第2 次连接成功
第3 次连接成功
Exception in thread "main" java.net.ConnectException: Connection refused: connect.....................
如果在测试方法代码最后加上一句server.service();运行结果为
第1 次连接成功
第2 次连接成功
第3 次连接成功
…
第100 次连接成功 ,可以看到100次连接可以成功获得建立
[b]绑定IP地址:[/b]
如果主机只有一个IP 地址,那么默认情况下,服务器程序就与该IP 地址绑定。ServerSocket
构造方法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(8000,10,InetAddress.getByName("192.168.3.4"));
[b]默认构造:[/b]
ServerSocket 有一个不带参数的默认构造方法。通过该方法创建的
ServerSocket 不与任何端口绑定,接下来还需要通过bind()方法与特定端口绑
定。这个默认构造方法的用途是,允许服务器在绑定到特定端口之前,先设置
ServerSocket 的一些选项。因为一旦服务器与特定端口绑定,有些选项就不能
再改变了。
ServerSocket serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(8888));
这样设置是有效的,但是如果吧第二句和第三句位置互换就失效了。
当服务器正在进行发送数据的操作时,如果客户端断开了连接,那么服务器端会抛出一个IOException的子类SocketException 异常:
java.net.SocketException: Connection reset by peer
这只是服务器与单个客户通信中出现的异常,这种异常应该被捕获,使得服务器能继续与其他客户通信。
while (true) {
Socket socket=null;
try {
socket = serverSocket.accept(); //从连接请求队列中取出一个连接
System.out.println("New connection accepted " +
socket.getInetAddress() + ":" +socket.getPort());
//接收和发送数据
…
}catch (IOException e) {
//这只是与单个客户通信时遇到的异常,可能是由于客户端过早断开连接引起的
//这种异常不应该中断整个while 循环
e.printStackTrace();
}finally {
try{
if(socket!=null)socket.close(); //与一个客户通信结束后,要关闭
Socket
}catch (IOException e) {e.printStackTrace();}
}
}
ServerSocket 有以下3 个选项。
1.SO_TIMEOUT:表示等待客户连接的超时时间。
2. SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。
3. SO_RCVBUF:表示接收数据的缓冲区的大小。
当服务器执行ServerSocket 的accept()方法时,如果连接请求队列为空,服务
器就会一直等待,直到接收到了客户连接才从accept()方法返回。如果设定了
超时时间,那么当服务器等待的时间超过了超时时间,就会抛出
SocketTimeoutException,它是InterruptedException 的子类。
SO_RCVBUF 表示服务器端的用于接收数据的缓冲区的大小,以字节为单位。一般
说来,传输大的连续的数据块(基于HTTP 或FTP 协议的数据传输)可以使用较
大的缓冲区,这可以减少传输数据的次数,从而提高传输数据的效率。而对于交
互式的通信(Telnet 和网络游戏),则应该采用小的缓冲区,确保能及时把小
批量的数据发送给对方。