没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
试读
28页
在客户/ 服务器通信模式中, 服务器端需要创建监听特定端口的 ServerSocket , ServerSocket 负责接收客户连接请求。本章首先介绍 ServerSocket 类的各个构造方法,以及成员方法的用法,接着介绍服务器如何用多线程来处理与多个客户的通信任务。 本章提供线程池的一种实现方式。线程池包括一个工作队列和若干工作线程。服务器程序向工作队列中加入与客户通信的任务,工作线程不断从工作队列中取出任务并执行它。本 章还介绍了 java.util.concurrent 包中的线程池类的用法,在服务器程序中可以直接使用它们。
资源推荐
资源详情
资源评论
PDF 文件使用 "pdfFactory Pro" 试用版本创建 àwww.fineprint.cn
3.1 构造 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 地址。
3.1.1 绑定端口
除了第一个不带参数的构造方法以外,其他构造方法都会使服务器与特定端口绑
定,该端口由参数 port 指定。例如,以下代码创建了一个与 80 端口绑定的服务器:
ServerSocket serverSocket=new ServerSocket(80);
如果运行时无法绑定到 80 端口,以上代码会抛出 IOException,更确切地说,是抛
出BindException,它是 IOException 的子类。BindException 一般是由以下原因造成的:
端口已经被其他服务器进程占用;
在某些操作系统中,如果没有以超级用户的身份来运行服务器程序,那么操
作系统不允许服务器绑定到 1~1023 之间的端口。
如果把参数 port 设为 0,表示由操作系统来为服务器分配一个任意可用的端口。由
操作系统分配的端口也称为匿名端口。对于多数服务器,会使用明确的端口,而不会使
用匿名端口,因为客户程序需要事先知道服务器的端口,才能方便地访问服务器。在某些
场合,匿名端口有着特殊的用途,本章 3.4 节会对此作介绍。
第 3 章
ServerSocket 用法详解
在 客 户/ 服务器通信模式中, 服务器端需要创建监听特定端口的 ServerSocket ,
ServerSocket 负责接收客户连接请求。本章首先介绍 ServerSocket 类的各个构造方法,以及成
员方法的用法,接着介绍服务器如何用多线程来处理与多个客户的通信任务。
本章提供线程池的一种实现方式。线程池包括一个工作队列和若干工作线程。服务器程
序向工作队列中加入与客户通信的任务,工作线程不断从工作队列中取出任务并执行它。本
章还介绍了 java.util.concurrent 包中的线程池类的用法,在服务器程序中可以直接使用它们。
PDF 文件使用 "pdfFactory Pro" 试用版本创建 àwww.fineprint.cn
Socket socket=new Socket(www.javathinker.org,80);
import java.net.*;
public class Client {
public static void main(String args[])throws Exception{
final int length=100;
String host="localhost";
int port=8000;
Socket[] sockets=new Socket[length];
for(int i=0;i<length;i++){
sockets[i]=new Socket(host, port);
System.out.println("第"+(i+1)+"次连接成功");
}
Thread.sleep(3000);
for(int i=0;i<length;i++){
sockets[i].close();
}
//试图建立 100 次连接
//断开连接
}
}
56
Java Netword Programming
设定客户连接请求队列的长度
当服务器进程运行时,可能会同时监听到多个客户的连接请求。例如,每当一个
客户进程执行以下代码:
就意味着在远程 www.javathinker.org 主机的 80 端口上,监听到了一个客户的连接
请求。管理客户连接请求的任务是由操作系统来完成的。操作系统把这些连接请求存
储在一个先进先出的队列中。许多操作系统限定了队列的最大长度,一般为 50。当队
列中的连接请求达到了队列的最大容量时,服务器进程所在的主机会拒绝新的连接请
求。只有当服务器进程通过 ServerSocket 的 accept()方法从队列中取出连接请求,使队
列腾出空位时,队列才能继续加入新的连接请求。
对于客户进程,如果它发出的连接请求被加入到服务器的队列中,就意味着客户
与服务器的连接建立成功,客户进程从 Socket 构造方法中正常返回。如果客户进程发
出的连接请求被服务器拒绝,Socket 构造方法就会抛出 ConnectionException。
ServerSocket 构造方法的 backlog 参数用来显式设置连接请求队列的长度,它将覆
盖操作系统限定的队列的最大长度。值得注意的是,在以下几种情况中,仍然会采用
操作系统限定的队列的最大长度:
backlog 参数的值大于操作系统限定的队列的最大长度;
backlog 参数的值小于或等于 0;
在 ServerSocket 构造方法中没有设置 backlog 参数。
以下例程 3-1 的Client.java 和例程 3-2 的 Server.java 用来演示服务器的连接请求队
列的特性。
例程 3-1 Client.java
3.1.2
PDF 文件使用 "pdfFactory Pro" 试用版本创建 àwww.fineprint.cn
import java.io.*;
import java.net.*;
public class Server {
private int port=8000;
private ServerSocket serverSocket;
public Server() throws IOException {
serverSocket = new ServerSocket(port,3);
System.out.println("服务器启动");
}
//连接请求队列的长度为 3
public void service() {
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 分钟
//server.service();
}
}
第 1 次连接成功
第 2 次连接成功
第 3 次连接成功
Exception in thread "main" java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
Java Network Programming
57
第 3 章
ServerSocket 用法详解
例程 3-2 Server.java
Client 试图与 Server 进行 100 次连接。在 Server 类中,把连接请求队列的长度设
为 3。这意味着当队列中有了 3 个连接请求时,如果 Client 再请求连接,就会被 Server
拒绝。下面按照以下步骤运行 Server 和 Client 程序。
(1) 把 Server 类的 main()方法中的“server.service();”这行程序代码注释掉。这
使得服务器与 8 000 端口绑定后,永远不会执行 serverSocket.accept()方法。这意味着队
列中的连接请求永远不会被取出。先运行 Server 程序,然后再运行 Client 程序,Client
程序的打印结果如下:
PDF 文件使用 "pdfFactory Pro" 试用版本创建 àwww.fineprint.cn
3.1.4
ServerSocket serverSocket=new ServerSocket(8000,10,InetAddress.getByName ("192.168.3.4"));
public static void main(String args[])throws Exception {
Server server=new Server();
//Thread.sleep(60000*10);
//睡眠 10 分钟
server.service();
}
第 1 次连接成功
第 2 次连接成功
第 3 次连接成功
…
第 100 次连接成功
58
Java Netword Programming
从以上打印结果可以看出,Client 与 Server 在成功地建立了 3 个连接后,就无法
再创建其余的连接了,因为服务器的队列已经满了。
(2) 把 Server 类的 main()方法按如下方式修改:
作了以上修改,服务器与 8 000 端口绑定后,就会在一个 while 循环中不断执行
serverSocket.accept()方法,该方法从队列中取出连接请求,使得队列能及时腾出空位,
以容纳新的连接请求。先运行 Server 程序,然后再运行 Client 程序,Client 程序的打印
结果如下:
从以上打印结果可以看出,此时 Client 能顺利与 Server 建立 100 次连接。
设定绑定的 IP 地址
如果主机只有一个 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 不
与任何端口绑定,接下来还需要通过 bind()方法与特定端口绑定。
这个默认构造方法的用途是, 允许服务器在绑定到特定端口之前,先设置
ServerSocket 的一些选项。因为一旦服务器与特定端口绑定,有些选项就不能再改变了。在
以下代码中,先把 ServerSocket 的 SO_REUSEADDR 选项设为 true,然后再把
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at Client.main(Client.java:10)
3.1.3
PDF 文件使用 "pdfFactory Pro" 试用版本创建 àwww.fineprint.cn
ServerSocket serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(8000));
//设置 ServerSocket 的选项
//与 8000 端口绑定
ServerSocket serverSocket=new ServerSocket(8000);
serverSocket.setReuseAddress(true);
//设置 ServerSocket 的选项
java.net.SocketException: Connection reset by peer
public void service() {
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();}
}
}
}
Java Network Programming
59
第 3 章
ServerSocket 用法详解
它与 8000 端口绑定:
如果把以上程序代码改为:
那么 serverSocket.setReuseAddress(true) 方 法 就 不 起 任 何 作 用 了 , 因 为 SO_
REUSEADDR 选项必须在服务器绑定端口之前设置才有效。
3.2 接收和关闭与客户的连接
ServerSocket 的 accept()方法从连接请求队列中取出一个客户的连接请求,然后创
建与客户连接的 Socket 对象,并将它返回。如果队列中没有连接请求,accept()方法就
会一直等待,直到接收到了连接请求才返回。
接下来,服务器从 Socket 对象中获得输入流和输出流,就能与客户交换数据。当
服务器正在进行发送数据的操作时,如果客户端断开了连接,那么服务器端会抛出一
个 IOException 的子类 SocketException 异常:
这只是服务器与单个客户通信中出现的异常,这种异常应该被捕获,使得服务器
能继续与其他客户通信。
以下程序显示了单线程服务器采用的通信流程:
与单个客户通信的代码放在一个 try 代码块中,如果遇到异常,该异常被 catch 代
剩余27页未读,继续阅读
资源评论
小小哭包
- 粉丝: 1899
- 资源: 3860
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 聊天系统(java+applet).zip
- 毕业设计:基于SSM的mysql-高校学生请假管理系统(源码 + 数据库 + 说明文档)
- 博客系统(struts+hibernate+spring).rar
- c语言学生成绩管理系统源码.zip
- 毕业设计:基于SSM的mysql-网约车用户服务平台(源码 + 数据库 + 说明文档)
- 内容管理系统(hibernate3+struts2+spring2)130224.rar
- 基于Java的班级管理系统课程设计源码
- 内容管理系统(hibernate3+struts2+spring2).rar
- 路由器刷breed Web控制台助手v5.8版本.rar
- Java 在 JEP 12 提供的特性预览
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功