欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > java网络编程TCP通信实战:共享聊天室

java网络编程TCP通信实战:共享聊天室

2025/10/16 5:11:57 来源:https://blog.csdn.net/m0_74217856/article/details/142065326  浏览:    关键词:java网络编程TCP通信实战:共享聊天室

目录

创建服务端 建立ServerSocket服务端。

接下来就是服务端线程的编写

前端ui登录界面

客户端线程

群聊界面


package server;import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;public class Server {//定义一个集合容器存储所有登录进来的客户端管道,以便将来群发消息给他们// 定义一个Map集合,键是存储客户端的管道,值是这个管道的用户名称。public static  final Map<Socket,String> onlinesSockets=new HashMap<>();public static void main(String[] args)  {System.out.println("启动服务端程序...");try {ServerSocket serverSocket = new ServerSocket(Constant.SERVER_PORT);while (true) {System.out.println("等待客户端连接...");Socket socket = serverSocket.accept();System.out.println("一个客户端连接成功...");new ServerReaderThread(socket).start();}}catch (Exception e){e.printStackTrace();}}
}

创建服务端 建立ServerSocket服务端。

使用while循环不断接受客户端发来的请求,再将获得的管道交给一个线程独立完成各自的任务,实现多个客户端访问。将所有管道放在一个map集合中,以便将来群发消息给他们。

接下来就是服务端线程的编写

package server;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;public class ServerReaderThread extends Thread {private Socket s;public ServerReaderThread(Socket s){this.s = s;//设置有参构造器,将socket传入}@Overridepublic void run() {try {//接收的消息可能有很多中类型:1登录消息(包含名称)2 群聊消息 3 私聊消息//所以客户端必须声明协议发送消息,//客户端发1、2、3代表登录消息、群聊消息、私聊消息//先从socket管道中接受客户端发送来的消息类型编号DataInputStream dis = new DataInputStream(s.getInputStream());while (true) {int type = dis.readInt();switch (type) {case 1://登录消息,接下来接收名称数据,在更新全部在线客户端的在线人数列表。String nickname = dis.readUTF();Server.onlinesSockets.put(s, nickname);//更新在线人数列表updateClientOnlineCUserslist();break;case 2://群聊消息 接下来接受群聊消息内容,再把群聊消息发送给全部在线客户端。String msg = dis.readUTF();sendMsgAll(msg);break;case 3://私聊消息 接受私聊消息内容,再把私聊消息发送给指定的客户端。break;}}} catch (Exception e) {System.out.println("客户端下线了:" + s.getInetAddress().getHostAddress());Server.onlinesSockets.remove(s);updateClientOnlineCUserslist();}}private void updateClientOnlineCUserslist(){Collection<String>onLineUsers = Server.onlinesSockets.values();for(Socket socket:Server.onlinesSockets.keySet()){try {DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(1);//告诉群聊列表消息的类型dos.writeInt(onLineUsers.size());for(String nickname:onLineUsers){dos.writeUTF(nickname);}dos.flush();} catch (Exception e) {e.printStackTrace();}}}private void sendMsgAll(String msg){StringBuilder sb=new StringBuilder();String name=Server.onlinesSockets.get(s);//获取当前时间LocalDateTime now = LocalDateTime.now();DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss EEE a");String time = dtf.format(now);String sb1=sb.append(name).append(" ").append(time).append("\r\n").append(msg).append("\r\n").toString();for(Socket socket:Server.onlinesSockets.keySet()){try {DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(2);//告诉群聊消息的类型dos.writeUTF(sb1);dos.flush();}catch (Exception e){e.printStackTrace();}}}
}

前端ui登录界面

package com.acheng.ui;import Client.ConstantClient;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataOutputStream;
import java.net.Socket;public class ChatEntryFrame extends JFrame {private JTextField nicknameField;private JButton enterButton;private JButton cancelButton;private Socket socket;public ChatEntryFrame() {// 设置窗口标题setTitle("局域网聊天 - 进入界面");setSize(300, 150);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null); // 窗口居中// 创建面板JPanel panel = new JPanel();panel.setLayout(new GridLayout(3, 1)); // 3行1列的网格布局// 创建昵称输入框nicknameField = new JTextField();nicknameField.setBorder(BorderFactory.createTitledBorder("昵称"));panel.add(nicknameField);// 创建按钮面板JPanel buttonPanel = new JPanel();enterButton = new JButton("登录");cancelButton = new JButton("取消");// 添加按钮事件enterButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String nickname = nicknameField.getText();//获取昵称if (!nickname.isEmpty()) {// TODO: 处理进入聊天逻辑//立即发送登录消息给服务端程序。//请求一个socket管道,建立与服务端的连接。try {login(nickname);new ChatApp(nickname, socket);}catch (Exception e1){e1.printStackTrace();}System.out.println("进入聊天,昵称: " + nickname);dispose(); // 关闭当前窗口} else {JOptionPane.showMessageDialog(null, "请输入昵称!", "错误", JOptionPane.ERROR_MESSAGE);}}});cancelButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.exit(0); // 退出程序}});buttonPanel.add(enterButton);buttonPanel.add(cancelButton);panel.add(buttonPanel);// 将面板添加到窗口add(panel);setVisible(true);}public void login(String nickname) throws Exception{socket=new Socket(ConstantClient.CLIENT_IP, ConstantClient.CLIENT_PORT);DataOutputStream dos=new DataOutputStream(socket.getOutputStream());dos.writeInt(1);dos.writeUTF(nickname);dos.flush();}}

客户端线程

package com.acheng.ui;import java.io.DataInputStream;
import java.net.Socket;public class ClientReaderThread extends Thread {private Socket s;private ChatApp frame;private DataInputStream dis;public ClientReaderThread(Socket s, ChatApp frame ){this.s = s;this.frame = frame;}@Overridepublic void run(){try {dis = new DataInputStream(s.getInputStream());while (true) {//从socket管道中读取服务端发送来的消息//客户端发1、在线人数更新的数据 2 群聊消息//先从socket管道中接受客户端发送来的消息类型编号int type = dis.readInt();//根据消息类型编号,判断客户端发送的是哪种消息switch (type){case 1://服务端发来的在线人数更新消息updateClientOnlineUserList(dis);break;case 2://群聊消息,从socket管道中读取消息内容getMsgtoWin();//将群聊消息显示到聊天界面上break;case 3://私聊消息,从socket管道中读取消息内容}}}catch (Exception e) {e.printStackTrace();}}private void updateClientOnlineUserList(DataInputStream dis)throws Exception{//1、先从socket管道中读取在线人数//读取有多少个在线用户int count =dis.readInt();//循环读取多个用户信息String[] names = new String[count];for(int i=0;i<count;i++){String nickname = dis.readUTF();names[i] = nickname;}//将集合中的数据显示到客户端的在线用户列表中frame.updateOnlineUsers(names);}private void getMsgtoWin()throws Exception{String msg = dis.readUTF();frame.setMsgTowin(msg);}
}

群聊界面

package com.acheng.ui;import javax.swing.*;
import java.awt.*;
import java.io.DataOutputStream;
import java.net.Socket;public class ChatApp extends JFrame {private JFrame frame;private JTextArea messageDisplayArea;private JList<String> onlineUsersList;private DefaultListModel<String> onlineUsersListModel;private JTextField messageInputField;private JButton sendButton;private Socket socket;private String name;public ChatApp(String name, Socket socket) {// 创建主框架this.socket = socket;this.name = name; // 保存昵称frame = new JFrame(name+"的群聊界面");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(600, 400);frame.setLayout(new BorderLayout());// 消息展示框messageDisplayArea = new JTextArea();messageDisplayArea.setEditable(false);JScrollPane messageScrollPane = new JScrollPane(messageDisplayArea);frame.add(messageScrollPane, BorderLayout.CENTER);// 在线人数展示框onlineUsersListModel = new DefaultListModel<>();onlineUsersList = new JList<>(onlineUsersListModel);JScrollPane onlineUsersScrollPane = new JScrollPane(onlineUsersList);onlineUsersScrollPane.setPreferredSize(new Dimension(150, 0));frame.add(onlineUsersScrollPane, BorderLayout.EAST);// 消息发送框和发送按钮JPanel inputPanel = new JPanel();inputPanel.setLayout(new BorderLayout());messageInputField = new JTextField();sendButton = new JButton("发送");inputPanel.add(messageInputField, BorderLayout.CENTER);inputPanel.add(sendButton, BorderLayout.EAST);frame.add(inputPanel, BorderLayout.SOUTH);// 发送按钮的事件处理sendButton.addActionListener(e -> {String message = messageInputField.getText(); // 获取输入框中的文本if (!message.isEmpty()) {sendMessage(message);messageInputField.setText(""); // 清空输入框}});// 显示框架frame.setVisible(true);new ClientReaderThread(socket, this).start();}public void sendMessage(String message) {try {DataOutputStream dos = new DataOutputStream(socket.getOutputStream());dos.writeInt(2); // 消息类型dos.writeUTF(message);dos.flush();} catch (Exception e) {e.printStackTrace();}}public void updateOnlineUsers(String[] onLineNames) {// 更新在线用户列表onlineUsersList.setListData(onLineNames);}public void setMsgTowin(String msg) {SwingUtilities.invokeLater(() -> {messageDisplayArea.append(msg + "\n");});}
}
package Client;public class ConstantClient {public static final int CLIENT_PORT = 6666;public static final String CLIENT_IP = "127.0.0.1";
}
package server;public class Constant {public static final int SERVER_PORT = 6666;
}
import com.acheng.ui.ChatEntryFrame;public class App {public static void main(String[] args) {new ChatEntryFrame();}
}

界面展示

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词