import java.io.*;import java.net.Socket;//聊天室客户机:发送消息、接收别人发送的消息public class Client { public static void clientRequest() throws IOException { //建立客户机,与服务器建立连接 Socket client = new Socket("localhost", 8888); //创建一个线程用于接收消息 new Thread(new Receive(client)).start(); //本线程专用于送发消息 send.clientSend(client); } //封装内部类:发送消息 private static class send{ private static void clientSend(Socket client) throws IOException { boolean isRunning = true; String msg; System.out.println("已连接服务"); //利用IO流进行数据传输 //从键盘获取输入 BufferedReader is = new BufferedReader(new InputStreamReader(System.in)); //并将获取到的内容发送出去 DataOutputStream os = new DataOutputStream(client.getOutputStream()); while (isRunning) { try { msg = is.readLine(); os.writeUTF(msg); } catch (IOException e) { isRunning = false; System.out.println("服务被停止,发送失败!"); is.close(); os.close(); client.close(); } } } } //封装内部类:接收消息 private static class Receive implements Runnable{ Socket client; DataInputStream dis; boolean isRunning = true; //构造器 private Receive(Socket client) { this.client = client; } //run方法:具体操作 @Override public void run() { //具体操作:接收消息 String result; while(isRunning){ try { dis = new DataInputStream(client.getInputStream()); result = dis.readUTF(); System.out.println(result); } catch (IOException e) { isRunning = false; } } try { dis.close(); } catch (IOException e) { e.printStackTrace(); } } }}
import java.net.Socket;//用户类:保存一个客户机的用户名和Socketpublic class User{ String userName; Socket userSocket; public User(String name, Socket client){ this.userName = name; this.userSocket = client; }}
import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.CopyOnWriteArrayList;//聊天室服务器:转发客户机发送的消息public class Server { //群聊容器 private static CopyOnWriteArrayList<User> all = new CopyOnWriteArrayList<User>(); public static void serverResponse() throws IOException { boolean isRunning = true; //建立服务器 ServerSocket server = new ServerSocket(8888); System.out.println("服务启动"); //监听端口,随时等待客户机连接,当一个客户机连接后,建立一条线程为其服务,随后继续监听端口 while(isRunning){ try{ Socket client = server.accept(); new Thread(new Channel(client)).start();//为这个客户机建立单独的消息转发服务 System.out.println("一个客户机进行了连接"); } catch (IOException e) { isRunning = false; System.out.println("服务停止!"); server.close(); } } } //封装内部类:转发器 提供消息转发服务:将客户机发送的消息转发给其他客户机 private static class Channel implements Runnable{ DataInputStream sis; DataOutputStream sos; Socket client; String name; //构造器 private Channel(Socket client){ try { //利用IO流进行数据传输 this.client = client; sis = new DataInputStream(client.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } //群聊 private void group(String msg) throws IOException { for (User c : all) {//一个客户机发送消息后,遍历容器将该条消息转发给其他客户机 if (c.userSocket != this.client) { sos = new DataOutputStream(c.userSocket.getOutputStream()); sos.writeUTF(msg); } } } //run方法:具体操作 @Override public void run() { //具体操作:获取用户名,并将用户类存入群聊容器 try { boolean flag = true; while(flag){ sos = new DataOutputStream(client.getOutputStream()); sos.writeUTF("请输入您的用户名:"); name = sis.readUTF(); int i = 1; for (User c : all) {//遍历容器验证用户名是否存在 if (c.userName.equals(name)) { sos.writeUTF("用户名已存在!"); break; }else{ i++; } } if(i > all.size()) flag = false; } User user = new User(name, client); all.add(user); group("欢迎"+name+"加入聊天!"); } catch (IOException e) { e.printStackTrace(); } String msg; boolean isRunning = true; //具体操作:转发消息 while(isRunning) { try { msg = sis.readUTF(); //转发私聊消息:@xxx:msg if(msg.startsWith("@")) { int idx = msg.indexOf(":"); String targetName = msg.substring(1, idx);//获取该条消息所@的用户的用户名 msg = "来自"+name+"的私聊:"+msg.substring(idx+1); for (User c : all) {//遍历容器找到该条消息所@的用户后转发消息 if (c.userName.equals(targetName)) { sos = new DataOutputStream(c.userSocket.getOutputStream()); sos.writeUTF(msg); break; } } //转发公共群聊消息 }else{ msg = (name + ":" + msg); group(msg); } } catch (IOException e) {//客户机断开连接以后会进行以下操作 isRunning = false;//停止对该客户机的转发服务 all.removeIf(c -> c.userSocket == client);//将该客户机从容器中移除 System.out.println("一个客户机断开了连接"); } } try { //释放资源,随后该线程结束 sis.close(); } catch (IOException e) { e.printStackTrace(); } } }}