通过程序建立了实际的概念之后,现在应该回到最开始的问题,socket是什么?是实现计算机通信的一种方式,这毫无疑问.但如何能够用最容易理解的语言比较形象而又不偏颇的描述它的原理呢?
bruce eckel 在他的《java 编程思想》一书中这样描述套接字:
套接字是一种软件抽象,用于表达两台机器之间的连接“终端”。对于一个给定的连接,每台机器上都有一个套接字,您也可以想象它们之间有一条虚拟的“电缆”,“电缆”的每一端都插入到套接字中。当然,机器之间的物理硬件和电缆连接都是完全未知的。抽象的全部目的是使我们无须知道不必知道的细节.
按我的理解,抽象点来说,一个socket就是一个电话听筒,你有一个,和你通话的人也有一个,只不过其中有一个人的听筒叫serversocket,另一个人的听筒叫socket.至于谁是serversocket,谁是socket,这不重要,因为客户端和服务器端本来就是相对的,可以互相转化的.通话的两个人通过拿起两个听筒建立了一条通道,这条通道通不通就要看是不是双方都拿起听筒了,假如只有一方拿起听筒,那就只能听到一些嘟嘟的声音,证明通道不同.这里,拿起听筒的过程就是socket初始化的过程.建立了通道之后,也就是大家都拿起听筒之后,通道两端的人就可以开始通话了.这里又有两个过程,即a对b说话,b接听,和b对a说话,a收听,这两个过程是通过两条线路完成的.传输在这两条线路上的,就是流.流隐藏了所有传输的细节,使得通信双方都认为,他们传过去的是声音,而不是编码.
前面写的服务器端的程序实际上是单任务版本,服务器对客户机的处理机制是在同一时间段内只能处理一个连接,因为handleconnection中采取的是不断循环的阻塞方法,检测到一个,就处理一个,然后再检测到一个,就再处理一个,如果有多个连接同时请求,那只能排队等候.这样的程序是无法在网络中应付多个连接的,因为你无法保证在同一时间内只有一个客户提出与服务器的连接请求,而用阻塞的方法应付多客户连接其速度之慢是可想而知的.
这样就催生了面向多连接的版本.显然,通过多线程可以来实现我们的要求.
由于要解决的是处理客户连接的问题,因此我们的工作只是在服务器端的程序当中修改.其原理不难推出,就是在检测到一个连接请求之后,马上建立一个线程去处理它,然后继续兼听下一个连接请求.所以,我们只需要将原来在handleconnection中的代码原封不动的放到线程的执行代码中,而在handleconnection中添加上新建线程的代码就可以了,十分简单.
同上一篇的风格一样,我们来观察各个部分的代码细节.
首先为这个多线程的版本创建类multithreadremotefileserver
看看这个类的定义
import java.io.*;
import java.net.*;
public class multithreadremotefileserver{
protected int listenport;
public multithreadremotefileserver(int alistenport){
}
public static void main(string[] args) {
}
public void acceptconnections() {
}
public void handleconnection(socket incomingconnection) {
}
}
public multithreadedremotefileserver(int alistenport) {
listenport = alistenport;
}先来看main()public static void main(string[] args) {
multithreadedremotefileserver server = new multithreadedremotefileserver(3000);
server.acceptconnections();
}public void acceptconnections() {
try {
serversocket server = new serversocket(listenport, 5);//注意到没有,建立服务器socket的时候多了一个参数,这个参数是用来指定能够同时申请连接的最大数目,缺省值是50
socket incomingconnection = null;
while (true) {
incomingconnection = server.accept();
handleconnection(incomingconnection);
}
} catch (bindexception e) {
system.out.println("unable to bind to port " + listenport);
} catch (ioexception e) {
system.out.println("unable to instantiate a serversocket on port: " + listenport);
}
}public void handleconnection(socket connectiontohandle) {
new thread(new connectionhandler(connectiontohandle)).start();
}
class connectionhandler implements runnable {
protected socket sockettohandle;
public connectionhandler(socket asockettohandle) {
sockettohandle = asockettohandle;//通过构造函数,将待处理的socket实例作为参数传送进来
}
public void run() {//原来对socket的读/写的代码都在这里了
try {
printwriter streamwriter = new printwriter(sockettohandle.getoutputstream());
bufferedreader streamreader = new bufferedreader(new inputstreamreader(sockettohandle.getinputstream()));
string filetoread = streamreader.readline();
bufferedreader filereader = new bufferedreader(new filereader(filetoread));
string line = null;
while ((line = filereader.readline()) != null)
streamwriter.println(line);
filereader.close();
streamwriter.close();
streamreader.close();
} catch (exception e) {
system.out.println("error handling a client: " + e);
}
}
}Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器