Socket编程之聊天室 - Go语言中文社区

Socket编程之聊天室


1.单线程模式:
创建服务端:
第一步,准备地址和端口;第二步,创建一个ServerSocket对象;
第三步,等待客户端连接;最后一步,数据接收和发送。

public class SingleThreadServer {
    public static void main(String[] args) {
        //1. 准备地址和端口
        int port  = 1314;
        try {
            //2. ServerSocket
            ServerSocket serverSocket = new ServerSocket(port);
            //3. 等待客户端连接
            Socket client = serverSocket.accept();
            //4. 数据接收和发送
            //4.1 接收
            InputStream in = client.getInputStream();
            Scanner scanner = new Scanner(in);
            System.out.println("客户端说:"+scanner.nextLine());
            //4.2 发送
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            printStream.println("欢迎,欢迎");
            printStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建客户端:
第一步,准备服务端地址和端口号;第二步,创建客户端Socket连接服务器,
最后一步,数据传输(数据的发送和接收)。

public class SingleThreadClient {
    public static void main(String[] args) {
        //1. 服务端地址,端口号
        String ip = "127.0.0.1";//本机IP地址
        int port = 1314;
        try {
            //2.Socket
            Socket client = new Socket(ip,port);
            //3.数据传输(键盘输入,输出到显示屏)
            //3.1 发送数据
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            printStream.println("服务器,我来了");
            printStream.flush();
            //3.2 接收数据
            InputStream in = client.getInputStream();
            Scanner scanner = new Scanner(in);
            System.out.println("来自服务端的数据:"+scanner.nextLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果如下:
在这里插入图片描述
在这里插入图片描述
2.多线程模式:
上面的Server和Client只是进行了简单的通信操作:服务器端接收到客户端连接之后,服务器端向客户端输出一个字符串,而客户端也只是读取服务器端的字符串后就退出了。
实际应用中的客户端则可能需要和服务器端保持长时间通信,即服务器端需要不断地读取客户端数据,并向客户端写入数据;客户端也不需要不断地读取服务器端数据,并向服务器端写入数据。
创建服务端:
首先创建一个与客户端交互的任务处理;

public class ClientHandler implements Runnable {
    //储存所有注册的客户端
    private static final Map<String, Socket> socketMap = new ConcurrentHashMap<>();
    private final Socket client;
    private String name;

    public ClientHandler(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            //获取客户端输入流
            InputStream in = this.client.getInputStream();
            Scanner scanner = new Scanner(in);
            while (true) {
                String line = scanner.nextLine();
                if (line.startsWith("register:")) {
                    String[] segments = line.split(";");
                    if (segments.length == 2 && segments[0].equals("register")) {
                        String name = segments[1];
                        register(name);
                    }
                    continue;
                }
                if (line.startsWith("groupChat:")) {
                    String[] segments = line.split(":");
                    if (segments.length == 2 && segments[0].equals("groupChat")) {
                        String message = segments[1];
                        groupChat(message);
                    }
                    continue;
                }
                if (line.startsWith("privateChat:")) {
                    String[] segments = line.split(":");
                    if (segments.length == 3 && segments[0].equals("privateChat")) {
                        String name = segments[1];
                        String message = segments[2];
                        privateChat(name, message);
                    }
                    continue;
                }
                if (line.equalsIgnoreCase("bye")) {
                    quitChat();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void quitChat() {
        socketMap.remove(this.name);
        System.out.println(this.name + "下线了");
        printOnlineClient();
    }

    private void privateChat(String name, String message) {
        Socket socket = socketMap.get(name);
        if (socket != null) {
            sendMessage(socket, this.name + " 说:" + message);
        }
    }

    private void groupChat(String message) {
        for(Map.Entry<String,Socket> entry:socketMap.entrySet()) {
            Socket socket = entry.getValue();
            if (socket == this.client) {
                continue;
            }
            sendMessage(socket, this.name + "说:" + message);
        }
    }

    private void register(String name) {
        this.name = name;
        socketMap.put(name,this.client);
        System.out.println(name + "注册到系统中");
        sendMessage(this.client, "欢迎," + name + "注册成功");
        printOnlineClient();
    }
    //打印当前在线客户人数
    private void printOnlineClient() {
        System.out.println("当前在线的客户端有:" + socketMap.size() + "个,名称列表如下:");
        for(String name:socketMap.keySet()) {//keySet()取得所有的key信息
            System.out.println(name);
        }
    }
    //发指定消息到客户端
    private void sendMessage(Socket client, String s) {
        try {
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            printStream.println(s);
            printStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建服务端主程序。

public class MultiThreadServer {
    public static void main(String[] args) {
        int port = 1314;
        final ExecutorService executorService = Executors.newFixedThreadPool(2 * Runtime.getRuntime().availableProcessors());
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            System.out.println("服务端启动,运行在:" + serverSocket.getLocalSocketAddress());
            while (true) {
                final Socket socket = serverSocket.accept();
                System.out.println("客户端连接,来自:" + socket.getRemoteSocketAddress());
                executorService.execute(new ClientHandler(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

创建客户端:
首先创建一个读取服务端信息线程;

public class ReadDataFromServerThread extends Thread{
    private Socket client;

    public ReadDataFromServerThread(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            InputStream in = client.getInputStream();
            Scanner scanner = new Scanner(in);
            while (true) {
                try {
                    String message = scanner.nextLine();
                    System.out.println("来自服务端>" +
                            message);
                }catch (NoSuchElementException e) {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

再创建一个发送信息给服务端的线程;

public class WriteDataToServerThread extends Thread{
    private Socket client;

    public WriteDataToServerThread(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.print("请输入>");
                String message = scanner.nextLine();
                printStream.println(message);
                printStream.flush();
                if(message.equals("bye")){
                    break;
                }
            }
            this.client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最后客户端主程序。

public class MultiThreadClient {
    public static void main(String[] args) {
        String ip = "127.0.0.1";//本机IP地址
        int port = 1314;
        try {
            final Socket socket = new Socket(ip,port);
            new WriteDataToServerThread(socket).start();
            new ReadDataFromServerThread(socket).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

先启动服务端,再启动多个客户端。
结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/asd0356/article/details/94394890
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-25 00:15:42
  • 阅读 ( 843 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢