Socket聊天室

2018-06-04  本文已影响0人  z七夜

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

上一篇下一篇

猜你喜欢

热点阅读