该例子可以实现多个客户端的聊天室功能,即任何一个客户端发送消息给服务器,服务器会转发给所有与它连接的客户端。因为服务器要维护与多个客户端的连接,这里用线程实现,每个客户端和服务器端连接后,服务器端都会开启一个线程,用于接收当前这个客户端的消息,并转发给所有的客户端。
该例子由3个Java类实现,客户端:tcp. EchoMultiClient,服务器端:tcp.
EchoMultiServer,tcp.EchoServerThread(服务器端使用的线程类)。
客户端类,该客户端发送消息和接收消息分别在一个线程中进行:
package test; import java.util.List; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class MultiServer { ServerSocket serverSocket; List<Socket> clients=new ArrayList<Socket>(); public MultiServer() { try { serverSocket=new ServerSocket(7); while(true) { Socket clientSocket=serverSocket.accept(); clients.add(clientSocket); new EchoServerThread(clientSocket,clients).start(); } }catch(IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new MultiServer(); } }
服务器端代码,该代码中每监听到客户端的一个连接,就调用线程类创建并启动一个线程对象。
服务器端代码:
package test; import java.util.List; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class MultiServer { ServerSocket serverSocket; List<Socket> clients=new ArrayList<Socket>(); public MultiServer() { try { serverSocket=new ServerSocket(7); while(true) { Socket clientSocket=serverSocket.accept(); clients.add(clientSocket); new EchoServerThread(clientSocket,clients).start(); } }catch(IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new MultiServer(); } }
服务器端使用的线程类代码:
package test; //服务器端使用的线程类 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetSocketAddress; import java.net.Socket; import java.util.List; public class EchoServerThread extends Thread{ Socket myClient; List<Socket> clients; String clientHostName; int clientPort; public EchoServerThread(Socket myClient,List<Socket> clients) { super(); this.myClient=myClient; this.clients=clients; } public void run() { InetSocketAddress clientAddress=(InetSocketAddress)myClient.getRemoteSocketAddress(); clientHostName=clientAddress.getHostName(); clientPort=clientAddress.getPort(); System.out.println("第"+clients.size()+"个客户端"+clientHostName+":"+clientPort+"已连接"); try { String inStr; BufferedReader in=new BufferedReader(new InputStreamReader(myClient.getInputStream())); while((inStr=in.readLine())!=null) { System.out.println(inStr+".来自"+clientHostName+":"+clientPort+""); for(Socket client:clients) { if(client!=null) { PrintWriter out=new PrintWriter(client.getOutputStream(),true); out.println(inStr+".来自"+clientHostName+":"+clientPort+""); } } } }catch(IOException e) { System.err.println(clientHostName+":"+clientPort+"退出了."); } } }
该程序运行时,先启动服务器端代码,再多次启动客户端。
例如以下运行效果,启动了服务器端后,启动了3次客户端,3个客户端分别发送消息,效果如下:
效果图: