java - 如何在socket编程中制作多条消息?

标签 java multithreading sockets datainputstream dataoutputstream

我有一个项目,其中我制作了一个聊天服务器,人们(客户端)连接并选择一个合作伙伴进行聊天。然而,只有当两个客户端发送消息并看到对方输入的内容时,他们才会聊天。我想要的是像 Whatsapp 这样的东西,我们可以一个接一个地发送许多消息,而无需等待其他客户端发送。

我尝试创建一个线程类,在其中调用聊天和其他内容,但从未成功。

//this is the client.java and this is the part of the code where they start chatting
do {
        System.out.print(dis.readUTF());
        System.out.println(dis.readUTF());
        send = in.next();
        dos.writeUTF(send);
        b = dis.readBoolean();
    } while (b);

//this is part of the chatserver.java where the connection is done they start chatting
class handleClient implements Runnable {

    private Socket s1;
    private Socket s2;
    private String name1;
    private String name2;

    public handleClient(Socket s1, Socket s2, String n1, String n2) {
        this.s1 = s1;
        this.s2 = s2;
        this.name1 = n1;
        this.name2 = n2;
    }

    @Override
    public void run() {
        String msg1 = "", msg2 = "";
        boolean b;
        try {
            DataOutputStream dos1 = new DataOutputStream(s1.getOutputStream());
            DataInputStream dis1 = new DataInputStream(s1.getInputStream());

            DataOutputStream dos2 = new DataOutputStream(s2.getOutputStream());
            DataInputStream dis2 = new DataInputStream(s2.getInputStream());

            do {
                dos1.writeUTF(name1 + ": ");
                dos2.writeUTF(name2 + ": ");
                dos2.writeUTF(name1 + ": " + msg1);
                msg1 = dis1.readUTF();
                dos1.writeUTF(name2 + ": " + msg2);
                msg2 = dis2.readUTF();

                b = !msg1.equals(name1 + " is out") && !msg2.equals(name2 + " is out");
                dos1.writeBoolean(b);
                dos2.writeBoolean(b);
            } while (b);

            dos1.close();
            dis1.close();
            dos2.close();
            dis2.close();
            s1.close();
            s2.close();
        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
    }
}

最佳答案

readUTF(),嗯,读取 UTF 字符串。在读完一个之前它不会返回。这就是为什么您希望并行地从不同的客户端读取消息,因此无论哪个客户端先发送消息都没关系,该消息将被读取并随后可以独立于其他客户端转发。一种方法是为每个客户端启动一个单独的读取器线程。
这是一个简单的聊天室服务器(我不想处理选择客户端,抱歉):

public class ChatServer {
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(5555);
        List<DataOutputStream> doss = new ArrayList<>();
        while (true) {
            Socket client = server.accept();
            synchronized(doss) {
                doss.add(new DataOutputStream(client.getOutputStream()));
            }
            new Thread(new Runnable() {
                public void run() {
                    try (DataInputStream dis = new DataInputStream(client.getInputStream())) {
                        while (true) {                    // <---------  per-client loop
                            String message=dis.readUTF();
                            synchronized (doss) {
                                for (DataOutputStream dos : doss)
                                    dos.writeUTF(message);
                            }
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

它有一个输出流的中央存储(doss),每个客户端有一个线程用于读取入站流。然后,线程从客户端读取字符串并将其永远转发到所有传出流(内部 while(true) 循环)。
在客户端,循环实际上是单行循环,一个用于读取消息并将其发送到服务器,另一个用于从服务器获取某些内容并将其打印在屏幕上:

public class ChatClient {
    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        System.out.print("Enter your nick: ");
        String name = s.nextLine();
        Socket socket = new Socket("localhost", 5555);
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        new Thread(new Runnable() {
            public void run() {
                try {
                    while (true)                              // <------- receiver loop, in thread
                        System.out.println(dis.readUTF());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
        dos.writeUTF(name + " has joined the conversation");
        while (true)                                          // <------- sender loop
            dos.writeUTF(name + ": " + s.nextLine());
    }
}

该东西与端口5555上的硬编码localhost一起工作,根本不提供错误处理(当客户端离开时服务器死亡)。它本来就很短。

关于java - 如何在socket编程中制作多条消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56212581/

相关文章:

java - 编译代码时出现错误: Could not find or load main class .

java - 在 JUnit 中检查异常的最佳实践是什么?

c# - 锁与 Interlocked.Exchange

c - 如何在缺少 stdatomic.h 的机器上拥有原子整数?

c - 为什么 SO_RCVTIMEO 超时在设置后会有所不同?

node.js - 如何在socket.io的房间中从客户端调用函数?

java - 在 Jackson 中展平嵌套属性

java - 非常简单的一步一步的 JBehave 设置教程?

linux - 多线程ping脚本

java - 为什么在使用 EasyMock.createMock 创建 mock 时 junit 测试失败?