在六里面的实例中,只有一个客户端和服务器进行数据传输。那多个客户端呢?
可以借助之前的多线程。客户端做的事情跟之前一样,都是向服务器发送请求和接受服务器给出的响应。服务器端监听到每一个客户端发送请求时对应开启一个线程。线程用来接受客户端的请求和对客户端进行响应,这本来是服务器端的功能。那我怎么让每一个线程跟每一个客户端对照上呢?因为每一个客户端有在服务器端有自己的对应Socket,所以可以让线程跟这个Socket绑定。那如何去绑定呢?可以在new一个线程的时候把客户端对应的Socket传进来做参数,这样就实现了绑定。
服务器:一直监听客户请求,一旦监听到客户请求,立即创建一个线程,开启线程。
线程:接受客户请求,给与客户一个响应。在线程的构造方法中去绑定客户端的Socket。
客户端:发送请求到服务器;接受服务器的响应。
实例
一、服务器端
服务器端要做的事情是一直监听客户的请求,每当有新的请求时,都创建一个线程,并且将与该客户端对应生成的Socket与该线程绑定。
因为要一直监听客户请求,所以可以采用死循环的方式来写:
ServerSocket serverSocket = new ServerSocket(5000);
while (true) {
Socket socket = serverSocket.accept();
LoginThread loginThread = new LoginThread(socket);
loginThread.start();
}
二、线程类
因为线程需要跟一个Socket对象绑定,所以在线程类中需要需要一个一Socket对象作为参数的构造方法。同时也要有一个socket的属性,以便在run方法中调用。
因为线程要负责接受客户端的请求和发送给客户端响应,所以这些动作都需要在run方法中写出。
public class LoginThread extends Thread {
private Socket socket;
public LoginThread(Socket socket) {
this.socket = socket;
}
public void run() {
try{
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
User user = (User)ois.readObject();
System.out.println(user.getUserName()+user.getPwd());
//java中提供了InetAdress类来获取访问我该服务器的客户端的地址,代码如下:
InetAddress ia = socket.getInetAddress();
String ip = ia.getHostAddress();
System.out.println("本次访问我服务器的客户端为:" + ip);
String reply = "朕知道了";
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write(reply);
bw.close();
os.close();
ois.close();
is.close();
socket.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
三、客户端
客户端主要还是想服务器发送请求和接受信息,代码跟之前一样。
四、总结
使用线程颇有点类似外包的感觉,只要你向我发送请求,我就把跟你的互动外包给一个线程。但是在accept方法的源码中,只有当该服务可用时,才会给你创建一个socket。而在我们这个实例中在客户端向服务器发送一个新的请求之前,在这个客户端之前的请求都已经结束了,所以服务器端才能一直处于可用状态。但是在实际中要是这个请求之前的其他请求没有结束呢?会发生什么样的事情?