练习:TCP协议实现一个简易聊天室

首先有一个工具类,将释放资源的方法封装:
因为socket和io流都有Closeable接口

public class ChatUtils {
    /*用于释放资源的工具类*/
    public static void close(Closeable...targets){
        for(Closeable target:targets){
            try {
                if(target!=null){
                target.close();}
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

多线程实现服务器端:

/*在线聊天室:服务器*/
public class ChatServer {
    private static CopyOnWriteArrayList<channel> clientlist = new CopyOnWriteArrayList<>();//定义一个容器,存储所有的客户线程,用CopyOnWrite线程安全

    public static void main(String[] args) throws IOException {
        System.out.println("-----Server-----");
        ServerSocket serverSocket = new ServerSocket(8888);//建立服务器
        while (true) {//服务器不关闭
            Socket client = serverSocket.accept();//阻塞式监听
            System.out.println("一个客户端建立了连接");
            channel c = new channel(client);
            clientlist.add(c);//客户端加入容器
            new Thread(c).start();
        }
    }


    static class channel implements Runnable {//一个channel代表接收一个客户端请求
        private Socket client;
        private DataInputStream dis;
        private DataOutputStream dos;
        boolean isrunning;
        private String name;//客户端名字
        public channel(Socket client) throws IOException {
            this.client = client;
            dis = new DataInputStream(client.getInputStream());
            dos = new DataOutputStream(client.getOutputStream());
            isrunning = true;
            name=receive();//接收客户端构造时传入的名字
            sendothers(name+"进入聊天室",true);
        }

        public String receive() {
            //接收客户端消息
            String data = "";
            try {
                data = dis.readUTF();
            } catch (IOException e) {
                System.out.println("服务器读取数据失败");
                release();//直接释放资源
            }
            return data;
        }

        public void send(String data) {
            //返回响应消息
            try {
                dos.writeUTF(data);
                dos.flush();
            } catch (IOException e) {
                System.out.println("服务器无响应");
                release();
            }

        }

        public void release() {
            this.isrunning = false;
            ChatUtils.close(dis, dos, client);//封装了释放资源的工具类,直接调用
            clientlist.remove(this);
            sendothers(this.name+"退出聊天室",true);
        }
        //群发消息:服务器作为中转站,接收客户端的消息,然后转发出去
        //新版本实现私聊功能:遍历数组得到线程名字
        private void sendothers(String data,boolean flag) {//flag判断是否为系统消息

           boolean isprivate=data.startsWith("@");
            if(isprivate){//如果是私聊消息则遍历
                int ind=data.indexOf(":");
               String datahead=data.substring(1,ind);
               String databody=data.substring(ind+1,data.length());
               int a=0;
                for (channel other : clientlist){
                    if(datahead.equals(other.name)){
                             other.send(this.name+"悄悄对你说:"+databody);
                             a=1;
                    }
                }
                if(a==0){
                    System.out.println("该用户不存在");
                    send("该用户不存在");
                }
            }
           //群发消息
          else {  for (channel other : clientlist){
                if(other==this){continue;}
               if(flag==false){ other.send(this.name+"对所有人说"+data);}
               else{other.send("系统:"+data);}

            }
        }}


        @Override
        public void run() {
            while (isrunning) {
                String msg = receive();
                System.out.println(msg);
                if (!msg.equals("")) {
                    sendothers(msg,false);
                }
            }
        }
    }
}

然后是客户端

public class ChatClient1 {
    public static void main(String[] args) throws IOException {
        System.out.println("请输入用户名:");
         BufferedReader br=new BufferedReader(new InputStreamReader(System.in));//得到客户端名字
        String name=br.readLine();
        Socket client=new Socket("localhost",8888);
        new Thread(new CilentSend(client,name)).start();
        new Thread(new CilentReceive(client)).start();

    }
}

在上面将客户端的发送与接收功能实现了封装:
发送功能:

/*封装客户端的发送方法*/
public class CilentSend implements Runnable{
   private BufferedReader br;
   private DataOutputStream dos;
   private Socket client;
   private String name;
    boolean isrunning;
   public CilentSend( Socket client,String name){
       this.name=name;
       br=new BufferedReader(new InputStreamReader(System.in));
       try {
           dos=new DataOutputStream(client.getOutputStream());
       } catch (IOException e) {
           e.printStackTrace();
       }
       isrunning=true;
      send(name);//将得到的客户端名字发送给服务器

   }

    @Override
    public void run() {
        System.out.println("-----对话框-----");
        while (isrunning){
            String msg = null;
            try {
                msg = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
                  send(msg);

        }
    }

    public void send(String msg){
        if(!msg.equals("")){
            try {
                dos.writeUTF(msg);
                dos.flush();
            } catch (IOException e) {
                System.out.println("客户端发送消息失败");
                release();
            }

    }}
    public void release(){
        this.isrunning=false;
        ChatUtils.close(dos,client);//封装了释放资源的工具类,直接调用
    }

}

接收功能:

public class CilentReceive implements Runnable{
    private Socket client;//插座作为参数
   private DataInputStream dis;//当接收的数据为java基本数据类型时选用数据输入流
   boolean isrunning;
    public CilentReceive(Socket client){
        try {
            dis=new DataInputStream(client.getInputStream());//实现插座的得到输入流方法
        } catch (IOException e) {
            e.printStackTrace();
        }
        isrunning=true;设定一个标志用于run方法循环。
    }

    @Override
    public void run() {
        while (isrunning){
        String data = null;
        try {
            data = dis.readUTF();
        } catch (IOException e) {
            System.out.println("客户端读取数据失败");
            release();
        }
        if(!data.equals(""))
        System.out.println(data);
    }}
  
    public void release(){
        this.isrunning=false;
        ChatUtils.close(dis,client);//封装了释放资源的工具类,直接调用
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值