基于Socket,java简单群聊功能

本文介绍了一个基于Java的群聊系统实现,利用Socket、Swing和多线程技术完成多人实时通讯。系统包括服务器和客户端两部分,服务器负责消息转发,客户端实现消息收发。文章详细展示了代码结构和功能实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java简单群聊功能

​ 使用了Socket,swing,线程。

​ 原本是只准备写两人间的通信,是后来才想改成这样的,所以代码有点乱。

服务器类(Server)

有个set集合,当服务器群发消息时就要遍历它。

public class Server_ZZ {
	public static void main(String[] args) throws IOException {
		ServerSocket ss87 = new ServerSocket(10087);
        //用来存储连接的Socket
		HashSet<Socket> li=new HashSet<>();	
		//服务器界面
		Swing_Server sw=new Swing_Server();
		
		//不停的接受Socket,将其放入一个集合里面
		while(true){
			Socket s87 = ss87.accept();
			li.add(s87);
			sw.addSocket(s87, li);
		}
	}
}

服务器界面(Swing_Server)

发送消息的功能是在这个类中完成的,通过触发button的点击事件,来发送消息。用线程来接收消息

发送消息的流程为:

​ 通过Socket得到OutputStream os;

​ os.write()//写入你要发送的消息,要转换成byte[]型;

接受消息:

​ 因为消息是一直要接收的,如果不用线程则进行不了其他操作。RecepteThread类

public class Swing_Server extends JFrame {
	HashSet<Socket> li;
	Socket s;
	OutputStream os;
	String ip;//自己的ip地址
	String cip;//客户端的IP地址
	JTextArea ja1;
	
	
	public void addSocket(Socket soc,HashSet<Socket> li) throws IOException{
		s=soc;//当前集合通信
		this.li=li;//socket通信集合
		
		os= s.getOutputStream();//socket中的输出流		
		ip=InetAddress.getLocalHost().toString();//拿到自己的ip地址
		cip=s.getInetAddress().getHostAddress();//拿到对方的ip地址
		System.out.println(ip+"自己的ip地址");
		System.out.println(cip+"客户端的ip地址");
		
		setTitle("本机主机名/ip地址:"+ip);// 窗体标题
		
		// 当读到消息就把消息放入文本域,如果不用线程就会在这里一直执行
		RecepteThread rt = new ServerRecepteThread(s, this.ja1,this.li);
		new Thread(rt).start();
	}	
	public Swing_Server() throws IOException {
		setDefaultCloseOperation(EXIT_ON_CLOSE);// 关闭窗口时关闭程序
		//setTitle("本机主机名/ip地址:"+ip);// 窗体标题
		setResizable(false);// 禁止改变窗体大小

		setBounds(500, 100, 0, 0);// 窗体坐标
		setSize(700, 550);// 窗体大小
		setVisible(true);// 窗体可见
		setBackground(Color.white);

		Container c = getContentPane();// 拿到窗体的容器
		c.setLayout(new FlowLayout(FlowLayout.LEFT));

		// 消息文本域
		ja1 = new JTextArea();
		ja1.setEditable(false);// 不可编辑
		ja1.setSize(300, 500);// 文本框大小

		ja1.setFont(new Font("楷体", Font.PLAIN, 18));// 字体
		ja1.setLineWrap(true);// 自动换行
		ja1.setBackground(Color.WHITE);
		ja1.setRows(17);
		ja1.setColumns(67);
		
		// 发送消息文本域
		JTextArea ja2 = new JTextArea();
		ja2.setSize(100, 500);// 文本框大小
		ja2.setFont(new Font("楷体", Font.PLAIN, 16));
		ja2.setRows(7);// 行数
		ja2.setColumns(75);// 列数

		// 发送按钮
		JButton jb = new JButton();
		jb.setText("发送");
		
		//监听事件 当按下发送键时 发送消息
		jb.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				msg(ja1,ip,ja2.getText());// 在自己的屏幕上显示自己发的消息
				//写入流
				try {
					// 服务器自己发送的消息全部发一遍
					for (Socket so : li) {
						os = so.getOutputStream();
                        //将ip地址和消息内容用“&”隔开,这意味发送的消息里不能&
						String ipmsg=ip+"&"+ja2.getText();
						os.write(ipmsg.getBytes());
					}
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				ja2.setText("");// 清空文本
			}
		});
		// 将组件加入窗体
		c.add(ja1);
		c.add(ja2);
		c.add(jb);
		// 刷新
		c.validate();
	}
	// 在自己的屏幕上显示自己发的消息
	public static void msg(JTextArea j,String ip,String msg) {
		String str = "主机名/ip地址:" +ip+ "\n" + msg + "\n";
		j.append(str);
	}
}

服务器接收消息线程类(ServerRecepteThread)

这个类是继承的RecepteThread,RecepteThread就是我的客户端接收消息线程类,我重写了run方法。我这种写法是不对的,我开头也讲了,临时改的,就偷了点懒,这里应该用接口可能会更好点。

public class ServerRecepteThread extends RecepteThread implements Runnable {
	OutputStream os;
	HashSet<Socket> li;

	ServerRecepteThread(Socket s, JTextArea ja1, HashSet<Socket> li) throws IOException {
		super(s, ja1);
		this.li = li;
		this.os = s.getOutputStream();
	}

	@Override
	public void run() {
		try {
			int len;
			byte[] bys = new byte[1024];
			bi = s.getInputStream();
			String read;
			while (true) {
				// 接受消息
				len = bi.read(bys);
				read = new String(bys, 0, len);
				// 写入消息文本域ja1
				ja1.append("ip地址:" + cip + "\n" + read + "\n");

				// 服务器接收到客户端消息,就除该客户端都发送一遍
				for (Socket so : li) {
					if (!so.equals(s)) {
						os = so.getOutputStream();
						String reads = new String(cip + "&" + read);
						os.write(reads.getBytes());
					}
				}

				// 如果接受到“gg” 就结束
				if (read.equals("gg")) {
					s.close();
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

(客户端)接收消息线程类(RecepteThread)

public class RecepteThread implements Runnable {
	Socket s;
	JTextArea ja1;
	String cip;
	InputStream bi;

	//// socket 显示文本框
	RecepteThread(Socket s, JTextArea ja1) {
		this.s = s;
		this.ja1 = ja1;
		// 对方的ip地址
		this.cip = s.getInetAddress().getHostAddress();
	}

	@Override
	public void run() {
		try {
			int len;
			byte[] bys = new byte[1024];
			bi = s.getInputStream();
			String read;
			while (true) {
				// 接受消息
				len = bi.read(bys);
				read = new String(bys,