基于GUI的简单聊天室03

上一版本,客户端关闭后会出现“socket close”异常问题,这个版本用捕捉异常来解决,实际上只是把异常输出的语句改为用户退出之类,并没真正解决

服务器类

package Chat03;
/**
 * 相比01,加进了线程内部类,解决多个客户端连接时,服务器无法全部响应的问题。
 * @author Administrator
 *
 */

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.List;

public class ChatSever03 {
    // 布尔类型变量表示服务器是否开着
    boolean started = false;
    
    ServerSocket ss = null;

    List<Client> clients  = new ArrayList<Client>();
    
    public static void main(String[] args) {
            new ChatSever03().start();
    }
    
    public void start() {
        try {
            // 建立服务端,8888为端口号
            ss = new ServerSocket(8888);
            started = true;
        } 
        catch (BindException e) {
            System.out.println("Socket has been used !");
            System.out.println("请重启服务器 !");
            System.exit(0);
        }catch (IOException e) {
            e.printStackTrace();
        }
        // 服务器开启后,started变为true
        try {
            // 接受客户端的连接
            while (started) {
                Socket s = ss.accept();
                //构造Client对象
                Client c = new Client(s);
                clients.add(c);
                System.out.println("一个客户连接");
                //启动线程
                new Thread(c).start();
            }
        }  catch (Exception e) {
             e.printStackTrace();
        } finally {
                try {
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
    

    /**
     * 建立线程内部类
     */
    class Client implements Runnable{
        
        //要保有自己的Socket属性
        private Socket s = null;
        
        //自己的数据输入流
        private DataInputStream dis = null;
        
        private DataOutputStream dos = null;
        
        private boolean bConnected = false ;
        
        //采用构造方法,把Socket属性传进来
        public Client(Socket s) {
            //赋值给s 
            this.s = s ;
            //将dis初始化
            try {
                dis = new DataInputStream(s.getInputStream());
                dos = new DataOutputStream(s.getOutputStream());
                //连接成功后,bConnected 变为true
                bConnected = true ;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        /**
         * 发送信息的方法
         */
        public void send(String str) {
            try {
                dos.writeUTF(str);
System.out.println(str);
            } catch (IOException e) {
                clients.remove(this);
                System.out.println("对方退出了");
                //e.printStackTrace();
            }
        }
        @Override
        public void run() {
                try {
                    //while循环范围过大, 导致过一直报错;
                    while (bConnected) {
                        String str = dis.readUTF ();
//System.out.println(str);
                        //发送信息
                        for(int i = 0;i < clients.size(); i++) {
                            Client c = clients.get(i);
                            c.send(str);
//System.out.println(str);
                        }
                        
                        /*利用迭代器
                        for(Iterator 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 (EOFException e) {
                
                    System.out.println("Client Close !");
                }catch (IOException e) {
                    e.printStackTrace();
                }finally {
                        try {
                            if(dis != null) dis.close(); //再设置dis = null;
                            if(dos != null) dis.close();
                            if(s != null) s.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                }
            
        }
    }
}

 

posted @ 2019-04-25 00:09  朱健栋  阅读(386)  评论(0编辑  收藏  举报