Java TCP回送服务器-广播

Java TCP回送服务器-广播,java,tcp,server,Java,Tcp,Server,我有一个简单的echo服务器,我希望当连接的用户在服务器上键入任何内容时,所有其他客户端和该客户端都会收到一条消息+“|MOD” 它现在不会发送给所有客户,但它应该发送,我只是不知道我的代码中有什么错误,所以现在它只会将消息+“| MOD”发送给发送消息的客户,但不会发送给所有其他客户 我只是不明白,我有一个循环,通过所有客户端,但它仍然不会发送到所有客户端 服务器: package com.murplyx.server; import java.io.BufferedReader; impo

我有一个简单的echo服务器,我希望当连接的用户在服务器上键入任何内容时,所有其他客户端和该客户端都会收到一条消息+“|MOD”

它现在不会发送给所有客户,但它应该发送,我只是不知道我的代码中有什么错误,所以现在它只会将消息+“| MOD”发送给发送消息的客户,但不会发送给所有其他客户

我只是不明白,我有一个循环,通过所有客户端,但它仍然不会发送到所有客户端

服务器:

package com.murplyx.server;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {
    public static ServerSocket server;
    public static ArrayList<Socket> clients = new ArrayList<Socket>();

    public static void broadcast(String message) {
        try {
            for (Socket socket : clients) {
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

                out.println(message);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        try {
            server = new ServerSocket(9000);

            while (true) {
                clients.add(server.accept());

                for (Socket socket : clients) {
                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                    String line = in.readLine();

                    if (line != null) {
                        broadcast(line + " | MOD");
                    }
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
请帮忙


非常感谢。

您遇到的一个问题是,每个客户端都会无限重复地执行
读取标准输入、写入套接字、读取套接字、写入标准输出等操作

当您广播时,所有其他客户端通常仍处于
read stdin
阶段,因此它们不知道套接字上有等待读取的内容。他们仍在等待用户输入内容

最简单的选择之一是在每个客户机中启动两个线程-一个只处理
读取标准输入,写入标准输出,
,另一个处理
读取标准输入,写入标准输出

[另一个(可能更复杂的)选项是使用Java NIO同时轮询套接字和stdin以获取可用输入]


第二个问题是,您正在服务器中阻塞
accept
调用,然后依次读取每个套接字。您可以在一个线程中接受
,并让每个客户机只从该客户机读取另一个线程,然后重新广播给其他客户机。NIO在这里也是一个很好的选择-您可以轮询任何客户端的读取。

我不确定ArrayList如何使用套接字,因此我肯定会使用普通数组(请参阅此处编辑的代码)

有些我认为可以解决的问题:

在客户机上:

-停止关闭While循环中的套接字。在while循环之外关闭它(当客户端与服务器完成连接时)。另外,在循环外部声明套接字

注意这一点:当客户端使用套接字连接到服务器时,会自动为其提供一个设备端口,因此两个不同的设备将永远不会有相同的IP连接到服务器。TCP连接由两个端口组成:服务器套接字和客户端套接字,这些套接字由[deviceip:port,serverip:port](iirc)表示

-此外,在客户端上,不需要每次通过while循环时都声明一个新的读卡器。把这些都放在外面。while循环中的唯一内容应该是readline+print语句

-readLine是一种阻塞方法。(以防您不知道这意味着什么,这意味着readLine将使您的程序卡在那里,直到它实际读取一行为止。要绕过这一点,您可以使用if语句与
.ready()
函数组合使用。ready函数检查是否有任何内容需要“读入”,因此,如果没有输入,它就不会卡在“readLine”上

在服务器上:

-就像我前面说的,我会改回使用普通数组

-您的服务器仍将卡在.accept()上。因此,您将永远无法从客户端读取输入,除非每次连接后读取一次。您可以使用线程来侦听,它仍然可以工作

例如:(此代码与我附加的链接(也是您的问题)中的代码一致,将其放在服务器的while循环之前)

//创建一个tcp侦听器线程来处理侦听客户端
线程列表线程=新线程(){
公开募捐{
字符串介词句;
while(true){
//通过每个连接的插座循环

对于(int i=0;i In
Server.broadcast()
。如果我没记错的话,关闭PrintWriter将关闭底层套接字;如果您需要多次广播,我不会关闭它。@Fildor那也是-我还没有发现。请在代码中显示出来好吗?我在发布我的问题后想,所有客户端都有相同的IP,因为我测试它们时它们都有。我需要这样做我不知道这些写stdin和stdout是什么,所以当我说
读stdin
时,我指的是从
系统中读取。在
中,我在客户端尝试了这一点,但它只是终止了程序:与普通数组相比,使用
数组列表
没有交互作用。@Alnitak你能详细说明一下吗?“我不确定ArrayList是如何使用套接字的”-与使用普通数组的方式完全相同。他的代码中的这一部分可能很好,只是我只使用普通数组处理它,从未尝试实现ArrayList。感谢您的澄清!
package com.murplyx.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Client {
    public static void main(String args[]) {
        try {
            while (true) {
                Socket socket = new Socket("localhost", 9000);

                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

                BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

                out.println(input.readLine());

                System.out.println(in.readLine());

                socket.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// create a tcp listener thread to deal with listening to clients
Thread listenerThread = new Thread() {
    public void run() {
        String clientSentence;

        while (true) {
            //loop through each connected socket    
            for (int i = 0; i <= intLastSocket; i++) {
                Socket z = clientSocket[i];
                //make sure the socket is not null or closed (can't do anything 
                //with closed or null sockets           
                if ((z != null) && (!z.isClosed())) {
                    try {
                        // Deal with TCP input here
                        BufferedReader input = new BufferedReader(new 
                           InputStreamReader(z.getInputStream()));
                        // read in a line but only if there is one
                        if (input.ready()) {
                            clientSentence = input.readLine();
                        }
                    } catch (IOException x) {
                        printTCP("IOException caught when reading in: "
                                + x.toString());
                    }
                    if (clientSentence != null) {
                        System.out.println("Received from client: "
                                + clientSentence);
                        //send this message to the client
                        outputStream[i].println(clientSentence + " | MOD");
                    }

                    // clear the input
                    clientSentence = null;
                }
            }
        }
    }
};
listenerThread.start();