zoukankan      html  css  js  c++  java
  • java在线聊天项目0.7版 连接多个客户端问题,开启多个客户端后服务器端只接收到一个 对各种异常的补充处理

    问题的原因是

    while(connected) {
    String str=dis.readUTF();
    System.out.println(str);
    }

    不断循环执行,一直在死循环获取socket发送的信息,

    使得前面的语句

    s = ss.accept();
    connected=true;

    服务端接收新的客户端不能再被执行


    解决的方法——通过多线程技术

    当获得一个socket后,则开启一个多线程,让

    while(connected) {
    String str=dis.readUTF();
    System.out.println(str);
    }

    循环读取操作在多线程中完成

    这样每个socket获得之后都在各自的现成中完成自己的循环读取


    具体方法:

    首先在主函数main中建立一个关于线程的内部类,因为这个类外部其他类不需要,所以弄成内部类

    解决问题后效果图:

    服务器端代码有较大改动,当中遇到各种异常逐一解决,逻辑思路上不复杂,细节上注意解决了

    先开启客户端的各种异常

    客户端关闭后的异常提示

    服务端增加了ServerSocket的关闭

    服务端增加线程处理后无效果的调试——根据socket closed异常查明是

    在内部类Client中while循环写在了try的外边,导致socket已经被关闭,但循环依然在尽心,不断提示出错


    0.7版的最终服务器端代码如下:

    package com.swift;
    
    import java.io.DataInputStream;
    import java.io.EOFException;
    import java.io.IOException;
    import java.net.BindException;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class ChatServer {
    
        public static void main(String[] args) {
            new ChatServer().fun();
        }
    
        private void fun() {
            boolean started = false;
            ServerSocket ss = null;
            Socket s = null;
            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();
                }
            } 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 boolean connected = false;
    
            public Client(Socket s) {
                this.s = s;
                try {
                    this.dis = new DataInputStream(s.getInputStream());
                    connected = true;
                } 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);
                    }
                } 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();
                        }
                    }
                }
    
            }
    
        }
    }

    0.7版本的客户端代码改动不大,代码如下:

    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.DataOutputStream;
    import java.io.IOException;
    import java.net.ConnectException;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    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 = null;
        DataOutputStream dos = null;
        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.7");
            // 对窗口进行大的布局,分为三行一列,在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);
    
            final class ShareListener implements ActionListener {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    String taText = ta.getText();
                    String tfText = tf.getText() + "
    ";
                    String tfText1 = tf.getText();
                    ta.setText(taText + tfText);
                    tf.setText("");
                    // 当回车或发送按钮时,tfText发送到服务器
                    try {
                        dos.writeUTF(tfText1);
                        dos.flush();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
    
                }
            }
            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();
        }
    
        public void connect() {
            try {
                s = new Socket("127.0.0.1", 8888);
                System.out.println("connected!");
                dos = new DataOutputStream(s.getOutputStream());
    
            } 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();
        }
    
    }
  • 相关阅读:
    vim常用命令
    MYSQL用户管理
    RPM 命令
    Windows下使用xShell向远程Linux上传文件
    Linux PHP 安装过程出现的错误
    完整的 http 错误代码含义解释
    Linux gzip压缩输出
    高性能Mysql主从架构的复制原理及配置详解
    Mybatis多个参数传值方法
    jsp 九大内置对象和其作用详解
  • 原文地址:https://www.cnblogs.com/qingyundian/p/7954170.html
Copyright © 2011-2022 走看看