• java在线聊天项目0.9版 实现把服务端接收到的信息返回给每一个客户端窗口中显示功能之客户端接收


    客户端要不断接收服务端发来的信息

    与服务端不断接收客户端发来信息相同,使用线程的方法,在线程中循环接收

    客户端修改后代码如下:

    package com.swift;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.ConnectException;
    import java.net.Socket;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    public class ChatClientFrame extends JFrame {
    
        private static final long serialVersionUID = -118470059355655240L;
        Socket s;
        DataOutputStream dos;
        DataInputStream dis;
        private boolean connected = false;
        JLabel label_shang = new JLabel();
        JLabel label_xia = new JLabel();
        JTextField tf = new JTextField(38);
        JTextArea ta = new JTextArea(15, 50);
        JButton button = new JButton();
    
        public ChatClientFrame() {
            setBounds(200, 200, 500, 400);
            setTitle("客户端聊天工具 —— 0.9");
            // 对窗口进行大的布局,分为三行一列,在pBasic面板上添加三个面板shang zhong xia
            JPanel pBasic = new JPanel();
            pBasic.setLayout(new BorderLayout());// 不设置默认也是这种布局模式
            setContentPane(pBasic);// 把面板放在窗口上,不记得用this.关键字
            JPanel shang = new JPanel();
            JPanel zhong = new JPanel();
            JPanel xia = new JPanel();
            // 设置JPanel面板的大小
            shang.setSize(470, 25);
            zhong.setSize(470, 180);
            xia.setSize(470, 40);
            pBasic.add(shang, BorderLayout.NORTH);
            pBasic.add(zhong, BorderLayout.CENTER);
            pBasic.add(xia, BorderLayout.SOUTH);
            shang.setBackground(Color.red);
            zhong.setBackground(Color.yellow);
            xia.setBackground(Color.blue);
    
            label_shang.setText("聊天记录");
            shang.add(label_shang);
            ta.setLineWrap(true);// 自动换行
            JScrollPane scroll = new JScrollPane(ta);// 增加滚动条,以便不增加行数
            zhong.add(scroll);
            label_xia.setText("输入信息");
            xia.add(label_xia, BorderLayout.WEST);
            /*
             * 增加功能,窗口监听事件,窗口打开时设置光标焦点在tf文本域中
             */
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowOpened(WindowEvent e) {
                    tf.requestFocus();
                }
            });
            xia.add(tf, BorderLayout.CENTER);
            button.setText("发送");
            xia.add(button, BorderLayout.EAST);
    
            button.addActionListener(new ShareListener());
            tf.addActionListener(new ShareListener());
            pack();
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    disconnect();
                    System.exit(0);
                }
            });
            setVisible(true);
            // 创建窗体直接调用连接服务器
            connect();
            Thread t=new Thread(new ReceiveThread());
            t.start();
        }
    
        class ShareListener implements ActionListener {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                String tfText1 = tf.getText();
                tf.setText("");
                // 当回车或发送按钮时,tfText发送到服务器
                try {
                    dos.writeUTF(tfText1);
                    dos.flush();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
    
            }
        }
    
        class ReceiveThread implements Runnable {
    
            @Override
            public void run() {
                try {
                    while (connected) {
                        String str = dis.readUTF();
                        System.out.println(str);
                        ta.setText(ta.getText()+str+"
    ");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        public void connect() {
            try {
                s = new Socket("127.0.0.1", 8888);
                System.out.println("connected!");
                connected=true;
                dos = new DataOutputStream(s.getOutputStream());
                dis = new DataInputStream(s.getInputStream());
    
            } catch (ConnectException e) {
                System.out.println("服务端异常.........");
                System.out.println("请确认服务端是否开启.........");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void disconnect() {
            try {
                if (dos != null)
                    dos.close();
                if (s != null)
                    s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            new ChatClientFrame();
        }
    
    }

    同时也修改了,原来直接在窗口中调数据天加进窗口

    而是接收到服务端信息后再放到JTextArea中

    服务端窗口代码与上一版本基本没有改动,代码如下:

    package com.swift;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.EOFException;
    import java.io.IOException;
    import java.net.BindException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class ChatServer {
        
        boolean started = false;
        ServerSocket ss = null;
        Socket s = null;
        List<Client> clients=new ArrayList<Client>();  
        
        public static void main(String[] args) {
            new ChatServer().fun();
        }
    
        private void fun() {
            try {
                ss = new ServerSocket(8888);
                started = true;
            } catch (BindException e) {
                System.out.println("端口使用中......");
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                while (started) {
                    s = ss.accept();
                    System.out.println("a client connected success");
                    Client c = new Client(s);
                    new Thread(c).start();
                    clients.add(c);
                }
            } catch (EOFException e) {
                System.out.println("client has closed.");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    ss.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        class Client implements Runnable {
    
            private Socket s;
            private DataInputStream dis;
            private DataOutputStream dos;
            private boolean connected = false;
    
            public Client(Socket s) {
                this.s = s;
                try {
                    this.dis = new DataInputStream(s.getInputStream());
                    this.dos = new DataOutputStream(s.getOutputStream());
                    connected = true;
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            private void send(String str) {
                try {
                    dos.writeUTF(str);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                };
            }
            @Override
            public void run() {
                try {//注意:要包括while循环,如果try在while循环里,则出现socket closed异常
                    while (connected) {
                        String str = dis.readUTF();
                        System.out.println(str);
                        for(int i=0;i<clients.size();i++) {
                            Client c=clients.get(i);
                            c.send(str);
                        }
                        
    //                     for(Iterator<Client> it=clients.iterator();it.hasNext();) {
    //                         Client c=it.next();//方法二,不可取,有同步锁
    //                         c.send(str);
    //                     }
                        
    //                    Iterator<Client> it=clients.iterator();
    //                    while(it.hasNext()) {
    //                        Client c=it.next();//方法三,不可取,有同步锁,修改需要加锁(此时没修改)
    //                        c.send(str);
    //                    }
                         
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (dis != null) {
                        try {
                            dis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (s != null) {
                        try {
                            s.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(dos!=null) {
                        try {
                            dos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
    
            }
    
        }
    }

    0.9版功能已经基本完善,复制代码可自行测试

  • 相关阅读:
    希望走过的路成为未来的基石
    第三次个人作业--用例图设计
    第二次结对作业
    第一次结对作业
    第二次个人编程作业
    第一次个人编程作业(更新至2020.02.07)
    Springboot vue 前后分离 跨域 Activiti6 工作流 集成代码生成器 shiro权限
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    spring cloud springboot 框架源码 activiti工作流 前后分离 集成代码生成器
    java代码生成器 快速开发平台 二次开发 外包项目利器 springmvc SSM后台框架源码
  • 原文地址:https://www.cnblogs.com/qingyundian/p/7976293.html
Copyright © 2020-2023  润新知