2025年基于Socket,java简单群聊功能

基于Socket,java简单群聊功能java 简单群聊功能 使用了 Socket swing 线程 原本是只准备写两人间的通信 是后来才想改成这样的 所以代码有点乱 服务器类 Server 有个 set 集合 当服务器群发消息时就要遍历它 public class Server ZZ public

大家好,我是讯享网,很高兴认识大家。

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, 0, len); // 用&分割 String[] reads = read.split("&"); // 写入消息文本域ja1 ja1.append("ip地址:" + reads[0] + "\n" + reads[1] + "\n"); // 如果接受到“gg” 就结束 if (read.equals("gg")) { 
    s.close(); break; } } } catch (IOException e) { 
    e.printStackTrace(); } } } 

客户端类(Client)

public class Client { 
    public static void main(String[] args) throws UnknownHostException, IOException { 
    Socket s87 = new Socket(InetAddress.getByName(/*服务器的IP地址 字符串*/), 10087); System.out.println("Link start"); new Swing_Client(s87); } } 

客户端界面(Swing_Client)

这个类其实应该和服务端界面类,抽象后继承同一个父类,因为这两者有很多相同的代码,仅接收消息和发送消息的操作不同,界面设计是一样的。

讯享网public class Swing_Client extends JFrame { 
    public Swing_Client(Socket soc) throws IOException { 
    Socket s=soc;//当前集合通信 OutputStream os= s.getOutputStream();//socket中的输出流 String ip=InetAddress.getLocalHost().toString();//拿到自己的ip地址 String cip=s.getInetAddress().getHostAddress();//拿到对方的ip地址 System.out.println(ip+"自己的ip地址"); System.out.println(cip+"对方的ip地址"); 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)); // 消息文本域 JTextArea 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); //当读到消息就把消息放入文本域,如果不用线程就会在这里一直执行 RecepteThread rt=new RecepteThread(s,ja1); new Thread(rt).start(); // 发送消息文本域 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("发送"); //监听事件 当按下发送键时 write入流 jb.addActionListener(new ActionListener() { 
    @Override public void actionPerformed(ActionEvent e) { 
    msg(ja1,ip,ja2.getText());// 发送消息 //写入流 try { 
    os.write(ja2.getText().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); } } 

效果图:

在这里插入图片描述

带有主机名就是自己发的消息。服务器和客户端页面一样。要先开服务器,再开客户端。

总结:

代码有很多需要优化的地方,比如我上面提到的代码的复用,不能发送&,以及关闭窗口不能同时关闭线程问题,所以通过关闭窗口来下线再上线会报错。还有可以增加的功能:比如自己发的消息右对齐,别人的左对齐;右边空出来的可以做成 上线人列表,可以发起单独聊天等。下次在改! 下次!下次!咕咕咕

小讯
上一篇 2025-03-14 22:14
下一篇 2025-04-03 19:09

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/120182.html