美文网首页
Socket聊天室

Socket聊天室

作者: z七夜 | 来源:发表于2018-06-04 16:45 被阅读0次

    Socket

    socket基于TCP/IP协议,是面向连接的,请求---->响应
    服务器:ServerSocket
    客户端:Socket

    1.聊天室版本1

    1.1 client端

    public class ClientDemo1 {
         public static void main(String[] args) throws Exception{
              //创建客户端
             Socket socket = new Socket("localhost", 8888);
             //得到客户端输入流,解析出,服务端返回的数据
             DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
             String s = dataInputStream.readUTF();
             System.out.println(s);
             //得到客户端输出流,将客户端信息输出到服务端
             DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
             dataOutputStream.writeUTF("我是张三,您好服务端");
             dataOutputStream.flush();
         }
    }
    

    1.2 server端

    public static void main(String[] args) throws Exception{
              //创建服务端
             ServerSocket serverSocket = new ServerSocket(8888);
             //接收客户端连接,阻塞式,如果一个客户端连上之后,阻塞了,后面的就连不上;当有客户端连上之后,就会生成一个客户端
             Socket socket = serverSocket.accept();
             System.out.println("有客户端链接上了" );
            //得到客户端的输出流,输出信息
             DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
             dataOutputStream.writeUTF("欢迎你");
             dataOutputStream.flush();
             //得到客户端的输入流,输出客户端传过来的数据
             DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
             String s = dataInputStream.readUTF();
             System.out.println(s);
         }
    

    效果:
    当客户端连上之后,服务端返回数据,客户端接收,然后发送数据给服务端,服务端接收

    client
    server

    缺点:
    1.当客户端连上服务端之后,服务端就关闭了,而且客户端数据,是固定的数据,不能达到良好的聊天效果
    2.客户端只能先发送数据,然后服务端根据客户端数据返回,

    2.聊天室版本2

    2.1 客户端

    
     public static void main(String[] args) throws Exception{
    
             Socket socket = new Socket("localhost", 9999);
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
             DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
             DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
             while (true) {
                 dataOutputStream.writeUTF(bufferedReader.readLine());
                 dataOutputStream.flush();
                 //得到服务端的数据
                 String s = dataInputStream.readUTF();
                 System.out.println(s);
             }
         }
    

    根据控制台输入的数据,将数据发送给服务端,使用while循环,是想可以一直输入信息和接收信息,不会关闭客户端

    2.2 服务端

    public static void main(String[] args) throws Exception{
    
             ServerSocket serverSocket = new ServerSocket(9999);
    
             //接收客户端连接,阻塞式
             Socket socket = serverSocket.accept();
             while (true) {
                 //接收客户端传来的数据
                 DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
                 String s = dataInputStream.readUTF();
                 System.out.println(s);
    
                 //发送给客户端数据
                 DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                 dataOutputStream.writeUTF("欢迎你"+s);
                 dataOutputStream.flush();
             }
         }
    

    可以一直和客户端聊天,
    效果:


    client server

    缺点:
    1.只能一个客户端连接服务端,发送信息,别的客户端连接之后,服务端不会响应
    2.客户端只能先发送数据,然后服务端根据客户端数据返回,


    client2

    3.聊天室终极版本

    需求:

    聊天室中,多个客户端进行群聊,服务器进行数据的转发,
    客户端进行私聊: 只需要@xxx: 想说的话, 这个信息就只能被xxx收到,如果不按这种格式发信息,就是群聊,所有人都会接受到信息

    问题:
    1.服务端只能有一个客户端连接
    2.客户端读取和写出数据有先后顺序

    改进:
    1.在服务端,需要为每个客户端开辟一条线程,每个客户端之间互不影响
    2.客户端,为读取和写出数据分别开辟线程,互不影响

    3.1server端

    public class ServerDemo3 {
    
        List<MyChannel> myChannelList = new ArrayList<>();
    
        public static void main(String[] args) throws Exception{
    
            new ServerDemo3().start();
        }
    
        public void start() throws Exception{
    
            ServerSocket serverSocket = new ServerSocket(8888);
    
            while (true) {
                //接收客户端连接,阻塞式
                Socket socket = serverSocket.accept();
                MyChannel myChannel = new MyChannel(socket);
                myChannelList.add(myChannel);//将创建的客户端通道集中管理
    
                new Thread(myChannel).start();//开启通道
    
            }
    
    
        }
    
        //为每一个客户端开辟一条线程
        class MyChannel implements Runnable{
            private DataInputStream dataInputStream = null;
            private DataOutputStream dataOutputStream =null;
    
            private boolean isRunning = true;
    
            private String name;//用户名称
    
            //初始化信息
            public MyChannel(Socket socket){
                try {
                    dataInputStream = new DataInputStream(socket.getInputStream());
                    dataOutputStream = new DataOutputStream(socket.getOutputStream());
    
                    this.name = dataInputStream.readUTF();
                    send("欢迎进入聊天室");
                    sendOthers(name+"加入了聊天室",false);
                } catch (IOException e) {
                    CloseUtils.CloseAll(dataInputStream,dataOutputStream);
                    isRunning = false;
                }
            }
    
            public String recive(){
                String msg = "";
                try {
                    msg = dataInputStream.readUTF();
                } catch (IOException e) {
                    CloseUtils.CloseAll(dataInputStream,dataOutputStream);
                    isRunning = false;
                    myChannelList.remove(this);
                }
                return msg;
            }
    
    
            /**
             * 发送信息
             * @param msg
             */
            public void send(String msg){
                try {
                    dataOutputStream.writeUTF(msg);
                } catch (IOException e) {
                    isRunning = false;
                    CloseUtils.CloseAll(dataOutputStream,dataInputStream);
                    myChannelList.remove(this);
                }
            }
    
    
            public void sendOthers(String msg,Boolean isUser){
    
                String name = this.name;//说话的人的名字
    
                //解析发送的数据,判断是否是私聊
                if (msg.startsWith("@")&&msg.indexOf(":")>-1&&isUser){
    
                    //被@的人的名字
                    String username = msg.substring(1, msg.indexOf(":"));
    
                    //发送的话
                    String content = msg.substring(msg.indexOf(":") + 1);
    
                    for (MyChannel myChannel : myChannelList){
                        if (myChannel.name.equals(username)){
                            myChannel.send(name+"悄悄的跟你说"+content);
                        }
                    }
    
    
                }else {
                    for (MyChannel myChannel : myChannelList) {
                        if (myChannel == this && isUser) {
                            myChannel.send("我说:" + msg);
                            continue;
                        }
                        if (isUser) {//如果是用户说话,把名字加上
                            myChannel.send(name + "说:" + msg);
                        }
                        if (!isUser) {//如果是系统公告,就直接打印
                            myChannel.send(msg);
                        }
    
                    }
                }
            }
            @Override
            public void run() {
                while (isRunning){
                    sendOthers(recive(),true);
                }
            }
        }
    
    }
    
    

    3.2 客户端

    因为客户端要读写分离,互不影响

    接受数据:

    public class Recive implements Runnable {
    
        //得到数据
        private DataInputStream dataInputStream = null;
        private boolean isRunning = true;
    
        public Recive(Socket socket){
            try {
                dataInputStream = new DataInputStream(socket.getInputStream());
            } catch (IOException e) {
                isRunning =false;
                CloseUtils.CloseAll(dataInputStream);
            }
        }
    
        public String recive(){
            String msg ="";
            try {
                msg = dataInputStream.readUTF();
    
            } catch (IOException e) {
                isRunning =false;
                CloseUtils.CloseAll(dataInputStream);
            }
            return msg;
        }
        @Override
        public void run() {
            while (isRunning){
                System.out.println(recive());
            }
        }
    }
    

    发送数据:

    public class Send implements Runnable {
    
    
        private BufferedReader bufferedReader = null;
    
        private DataOutputStream dataOutputStream = null;
    
        private boolean isRunning = true;
        private String name; //用户名称
    
        public Send(Socket socket,String name){
            try {
                bufferedReader = new BufferedReader(new InputStreamReader(System.in));
                dataOutputStream = new DataOutputStream(socket.getOutputStream());
                this.name = name;
                //当建立链接之后,发送姓名给服务端
                send(name);
    
            } catch (IOException e) {
                //e.printStackTrace();
                isRunning = false;
                CloseUtils.CloseAll(dataOutputStream,bufferedReader);
            }
        }
    
    
        public String getConsoleData(){
            try {
                return bufferedReader.readLine();
            } catch (IOException e) {
                isRunning = false;
                CloseUtils.CloseAll(dataOutputStream,bufferedReader);
            }
            return "";
        }
    
        /**
         * 发送信息的方法
         */
        public void send(String msg){
            try {
                if (msg!=null && !msg.equals("")) {
                    dataOutputStream.writeUTF(msg);
                    dataOutputStream.flush();
                }
    
            } catch (IOException e) {
                isRunning = false;
                CloseUtils.CloseAll(dataOutputStream,bufferedReader);
            }
        }
    
    
        @Override
        public void run() {
    
            while (isRunning){
                send(getConsoleData());
            }
    
        }
    }
    
    

    客户端:

    public static void main(String[] args) throws Exception{
    
            Socket socket = new Socket("localhost", 8888);
    
            System.out.println("请输入名称:");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            String name = bufferedReader.readLine();//得到名称
          /*  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
            dataOutputStream.writeUTF(bufferedReader.readLine());
            dataOutputStream.flush();*/
           new Thread(new Send(socket,name)).start();
    
           new Thread(new Recive(socket)).start();
    
        }
    

    源码:
    进群交流:552113611

    相关文章

      网友评论

          本文标题:Socket聊天室

          本文链接:https://www.haomeiwen.com/subject/flecsftx.html