java多线程聊天室(有图形界面)

您所在的位置:网站首页 用java编写聊天程序代码 java多线程聊天室(有图形界面)

java多线程聊天室(有图形界面)

#java多线程聊天室(有图形界面)| 来源: 网络整理| 查看: 265

聊天室分客户端和服务端,可实现的功能: 多人聊天、退出聊天室、发送系统消息

直接上代码吧。 (我用的是idea)

服务端:

package chat; import javax.swing.*; import javax.swing.JTextField; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; class server extends JFrame implements Runnable, ListSelectionListener, ActionListener { private ServerSocket ss;//建立socket private ArrayList users = new ArrayList(); //容量能够动态增长的数组 DefaultListModel dl = new DefaultListModel(); private JList userList = new JList(dl);//显示对象列表并且允许用户选择一个或多个项的组件。单独的模型 ListModel 维护列表的内容。 //消息输入栏 JTextField jtf = new JTextField(); public server() throws Exception{ this.setTitle("服务器端");//窗口名称 this.add(userList, "North"); JPanel jpl = new JPanel(); this.add(jpl, "South"); //将消息输入栏设为一栏 jtf.setColumns(1); jpl.setLayout(new BorderLayout()); jpl.add(jtf, BorderLayout.NORTH); JButton jbt1 = new JButton("发送消息"); jpl.add(jbt1, BorderLayout.WEST);//发送消息 //发送消息 jbt1.addActionListener(this); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setLocation(400,100); this.setSize(500, 400); this.setVisible(true); this.setAlwaysOnTop(true); ss = new ServerSocket(80);//绑定80端口 new Thread(this).start();//监听用户端的加入 } @Override public void run() { while(true){ try{ Socket s = ss.accept();//等待客户端连接 ChatThread ct = new ChatThread(s); //为该客户开一个线程 users.add(ct); //将每个线程加入到users ct.start(); }catch (Exception ex){ ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(this,"服务器异常!"); System.exit(0); } } } //发送消息按钮点击事件监听 @Override public void actionPerformed(ActionEvent e) { String label = e.getActionCommand(); if(label.equals("发送消息")){ handleAll(); } } public void handleAll(){ if(!jtf.getText().equals("")){ sendMessage("ALL#" + jtf.getText()); //发送完后,输入框中内容为空 jtf.setText(""); } }//发送消息 public class ChatThread extends Thread{ Socket s; private BufferedReader br; private PrintStream ps; public boolean canRun = true; String nickName = null; public ChatThread(Socket s) throws Exception{ this.s = s; br = new BufferedReader(new InputStreamReader(s.getInputStream()));//读取服客户端数据 ps = new PrintStream(s.getOutputStream());//向客户端发送数据 } public void run(){ while(canRun){ try{ String msg = br.readLine();//接收客户端发来的消息 String[] strs = msg.split("#"); switch (strs[0]) { case "LOGIN" -> { //收到来自客户端的登录消息 nickName = strs[1]; dl.addElement(nickName); userList.repaint(); sendMessage(msg); } case "MSG", "FSMSG" -> sendMessage(msg); case "OFFLINE" -> { //收到来自客户端的退出消息 sendMessage(msg); dl.removeElement(strs[1]); // 更新当前在聊天室内的用户List列表 userList.repaint(); } } }catch (Exception ignored){ System.out.println("出现异常"); } } } } public void sendMessage(String msg){ //服务器端发送给所有用户 for(ChatThread ct : users){ ct.ps.println(msg); } } @Override public void valueChanged(ListSelectionEvent e) { // TODO 自动生成的方法存根 } public static void main(String[] args) throws Exception{ new server(); } }

客户端:

package chat; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; public class client1 extends JFrame implements Runnable,ActionListener { //north private JMenuBar bar = new JMenuBar(); private JMenu menu = new JMenu("关于"); private JMenuItem about = new JMenuItem("聊天室信息"); private JMenuItem exit = new JMenuItem("退出聊天室"); JPanel north = new JPanel(); DefaultListModel dl = new DefaultListModel();//用来修改JList private JList userList = new JList(dl);//用来展示和选择 //center面板 JPanel center = new JPanel(); JTextArea jta = new JTextArea(10,20); JScrollPane js = new JScrollPane(jta); JPanel operPane = new JPanel();//发送消息的操作面板 JLabel input = new JLabel("请输入:"); JTextField jtf = new JTextField(24); private JButton jbt = new JButton("发送消息"); private BufferedReader br = null; private PrintStream ps = null; private String nickName = null; public client1() throws Exception{ //north 菜单栏 bar.add(menu); menu.add(about); menu.add(exit); about.addActionListener(this); exit.addActionListener(this); BorderLayout bl = new BorderLayout(); north.setLayout(bl); north.add(bar,BorderLayout.NORTH); add(north,BorderLayout.NORTH); //center 聊天消息框 发送消息操作面板 jta.setEditable(false);//消息显示框是不能编辑的 BorderLayout bl3 = new BorderLayout(); center.setLayout(bl3); FlowLayout fl = new FlowLayout(FlowLayout.LEFT); operPane.setLayout(fl); operPane.add(input); operPane.add(jtf); operPane.add(jbt); center.add(js,BorderLayout.CENTER);//js消息展示框JScrollPane center.add(operPane,BorderLayout.SOUTH); add(center,BorderLayout.CENTER); js.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);//需要时才显示滚动条 //鼠标事件,点击 jbt.addActionListener(this); this.setDefaultCloseOperation(EXIT_ON_CLOSE); nickName = JOptionPane.showInputDialog("用户名:"); this.setTitle("聊天室-"+nickName); this.setSize(500,400); this.setVisible(true); Socket s = new Socket("10.100.35.39", 80);//连接到指定主机(即本机)的指定端口号80 br = new BufferedReader(new InputStreamReader(s.getInputStream()));//读取服务器端数据 ps = new PrintStream(s.getOutputStream());//向服务器端发送数据 new Thread(this).start(); ps.println("LOGIN#" + nickName);//发送登录信息,消息格式:LOGIN#nickName jtf.setFocusable(true);//设置焦点 //键盘事件,实现当输完要发送的内容后,直接按回车键,实现发送 //监听键盘相应的控件必须是获得焦点的情况下才能起作用 jtf.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { ps.println("MSG#" + nickName + "#" + jtf.getText());//发送消息的格式:MSG#nickName#message //发送完后,是输入框中内容为空 jtf.setText(""); } } }); //监听系统关闭事件,退出时给服务器端发出指定消息 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { ps.println("OFFLINE#" + nickName);//发送下线信息,消息格式:OFFLINE#nickName } }); } public void run(){//客户端与服务器端发消息的线程 while (true){ try{ String msg = br.readLine();//读取服务器是否发送了消息给该客户端 String[] strs = msg.split("#"); //判断是否为服务器发来的登陆信息 if(strs[0].equals("LOGIN")){ if(!strs[1].equals(nickName)){//不是本人的上线消息就显示,本人的不显示 jta.append(strs[1] + "加入聊天室\n"); dl.addElement(strs[1]);//DefaultListModel来更改JList的内容 userList.repaint(); } }else if(strs[0].equals("MSG")){//接到服务器发送消息的信息 if(!strs[1].equals(nickName)){//别人发送的消息 jta.append(strs[1] + ":" + strs[2] + "\n"); }else{ jta.append("我:" + strs[2] + "\n"); } } else if(strs[0].equals("ALL")){ jta.append("系统消息:" + strs[1] + "\n"); } }catch (Exception ex){//如果服务器端出现问题,则客户端强制下线 JOptionPane.showMessageDialog(this, "聊天室已关闭。"); System.exit(0); } } } @Override public void actionPerformed(ActionEvent e) {//鼠标点击事件 String label = e.getActionCommand(); if(label.equals("发送消息")){ handleSend(); } else if(label.equals("聊天室信息")){ JOptionPane.showMessageDialog(this, "该聊天室由xxx制作\n感谢使用");//这里可以改成别的话,随你心意 }else if(label.equals("退出聊天室")){ JOptionPane.showMessageDialog(this, "您已成功退出!"); ps.println("OFFLINE#" + nickName); System.exit(0); } else{ System.out.println("不识别的事件"); } } public void handleSend(){//群发消息 //发送信息时标识一下来源 ps.println("MSG#" + nickName + "#" + jtf.getText()); //发送完后,是输入框中内容为空 jtf.setText(""); } public static void main(String[] args)throws Exception{ new client1(); } }

不是原创,源代码来自这里,删掉了很多,改了一点点。感谢这位博主的分享。

要实现多人聊天就多复制几个客户端(记得改名)再一起运行就好了。

如果要分别在两台机子上运行,实行不同机器之间的多人聊天,就把电脑的防火墙关掉,然后代码里的主机号改为服务器端所在的电脑的主机号,再ping一下看看是否连接成功就行了。 两台电脑连接成功之后非服务器端所在电脑只需要运行客户端程序,同时服务器端可以同时运行服务器端和客户端,这个问题不大。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3