在上一小节中,分别实现了服务器端程序和客户端程序,当一个客户端程序请求服务器端时,服务器端就会结束阻塞状态,完成程序的运行。实际上,很多服务器程序都是允许被多个应用访问的,例如门户网站可以被多个用户同时访问,因此服务器都是多线程的。下面通过一个图例来表示多个用户访问同一个服务器,如下所示:
上图中代表的是多个客户端访问同一个服务器端,服务器端为每个客户端创建一对应的 Socket,并且开启一个新的线程使两个 Socket 建立专线进行通信。接下来根据上图所示的通信方式上一小节的程序进行改进,如下所示:
import java.io.OutputStream;
import java.net.*;
public class Server {
public static void main(String[] args) throws Exception {
//创建 TCPServer 对象,并调用 listen()方法
new TCPServer().listen();
}
}
//TCPServer 服务端
class TCPServer{
private static final int PORT = 7788; //定义一个端口号
public void listen() throws Exception {
//创建 ServerSocket 对象,监听指定的端口
ServerSocket serverSocket = new ServerSocket(PORT);
while (true) {
//调用 ServerSocket 的 accept()方法与客户端建立连接
final Socket client = serverSocket.accept();
//开启一个新线程
new Thread() {
@Override
public void run() {
super.run();
//定义一个输出流对象
OutputStream os;
try {
os = client.getOutputStream(); //获取客户端的输出流
System.out.println("开始和客户端交互数据");
os.write("我爱你".getBytes());
Thread.sleep(5000); //使线程休眠 5000 毫秒
System.out.println("结束和客户端交互数据");
client.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
}
}
上述代码块中使用多线程的方式创建了一个服务器端程序。通过在 while 循环中调用 accept()方法,不停的接收客户端发送的请求,当与客户端建立连接后,就会开启一个新的线程,该线程会去处理客户端发送的数据,而主线程仍继续等待状态。
为了验证服务器端程序时候实现了多线程,首先运行服务器端程序,之后运行三个客户端程序,当运行第一个客户端程序时,服务器马上就进行数据处理,打印出“开始于客户端交互数据”,在运行第 2 个和第 3 个客户端程序,会发现服务端也立刻做出回应,3 个客户端会话结束后分别打印各自的结束消息,如下图所示。这说明通过多线程的方式可以实现多个用户对同一个服务器的访问。