简体   繁体   English

Java TCP Echo Server-广播

[英]Java TCP Echo Server - Broadcast

I have a simple echo server, and I want when a connected user types anything to the server, all other clients and that client will get a the message + " | MOD". 我有一个简单的回显服务器,我希望当连接的用户在服务器上键入任何内容时,所有其他客户端和该客户端都将收到一条消息+“ | MOD”。

It wont send to all clients now but it should and I just don't know what's wrong in my code, so now it will just send the message + " | MOD" to the client who sent the message but not to all others also as it should. 它现在不会发送给所有客户端,但是它应该并且我只是不知道我的代码出了什么问题,所以现在它将只发送消息+“ | MOD”给发送了消息的客户端,而不发送给所有其他用户。这应该。

I just don't get it, I have a loop that goes through all clients, but it still won't send to all. 我只是不明白,我有一个遍历所有客户端的循环,但是仍然不会发送给所有人。

SERVER: 服务器:

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();
        }
    }
}

CLIENT: 客户:

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();
        }
    }
}

Please help. 请帮忙。

Thanks alot. 非常感谢。

One of the issues you have is that each client will repeatedly do read stdin, write socket, read socket, write stdout, ... ad infinitum. 您遇到的问题之一是,每个客户端都会反复read stdin, write socket, read socket, write stdout, ...无限。

When you broadcast all other clients are still typically sat in the read stdin phase, so they don't know that there's stuff waiting to be read on the socket. 当广播时,所有其他客户端通常仍处于read stdin阶段,因此他们不知道套接字上有等待读取的内容。 They're still waiting for the user to enter something. 他们仍在等待用户输入内容。

One of the simplest options is to start two threads in each client - one just handles read stdin, write socket, ... and the other handles read socket, write stdout . 最简单的选择之一是在每个客户端中启动两个线程-一个仅处理read stdin, write socket, ... ,另一个处理read socket, write stdout

[Another (potentially more sophisticated) option us to use Java NIO to poll both the socket and stdin for available input at the same time ]. [另一个(可能更复杂)选项,我们可以使用Java NIO 同时 轮询两种插座和标准输入可用的输入。

A second issue is that you're blocking in the accept call in the server, and then reading from each socket in turn . 第二个问题是,你堵在accept服务器的呼叫,然后从每个插座依次阅读。 You might accept in one thread, and have another thread per client read from just the client, and rebroadcast to the others. 您可能会accept一个线程,并让每个客户端仅从该客户读取另一个线程,然后重新广播到其他线程。 NIO can also be a good option here - you can poll for reads any any client. NIO也是一个不错的选择-您可以轮询任何客户端的读取。

I'm not exactly sure how ArrayLists play with sockets, so I definitely would go back to using a normal array for it (see the edited code here Java EchoTCPServer - Send to all clients ) 我不确定ArrayLists如何与套接字一起玩,所以我肯定会回过头来使用普通的数组(请参阅此处的编辑代码Java EchoTCPServer-发送给所有客户端

Some things I see that I think can to be fixed: 我认为可以解决的一些问题:

On the Client: 在客户端上:

-Stop closing the socket in the While loop. -停止在While循环中关闭套接字。 Close it OUTSIDE the while loop (When the client is done with the server). 在while循环外关闭它(当客户端用服务器完成时)。 Also, declare the socket outside the Loop. 另外,在循环外声明套接字。

NOTE ON THIS : When a client makes a socket to connect to the server, it is automatically given a device port, so two different devices will never have the same IP connected to the server. 关于此提示 :客户端建立套接字以连接到服务器时,会自动为它提供设备端口,因此两个不同的设备永远不会将相同的IP连接到服务器。 A TCP connection consists of 2 ports, server socket and client socket, and the sockets are denoted by [deviceip:port,serverip:port] (iirc). TCP连接由服务器套接字和客户端套接字两个端口组成,并且套接字由[deviceip:port,serverip:port](iirc)表示。

-Also, on the client you don't need to declare a new reader everytime you move through the while loop. -此外,在客户端上,您无需每次通过while循环时都声明新的阅读器。 Put that all outside. 放在外面。 The only thing inside the while loop should be your readline + print statements. while循环中唯一的东西应该是您的readline + print语句。

-readLine is a blocking method. -readLine是一种阻止方法。 (just in case you don't know what that means, it means that readLine will make your program be stuck there until the it actually reads a line. To bypass this, you can use an if statement combined with the .ready() function. The ready function checks to see if there is anything to be "read in", so if there's no input it wont be stuck on "readLine". (以防万一,您不知道这意味着什么,这意味着readLine将使程序停留在该位置,直到它实际读取一行为止。要绕过该行,可以将if语句与.ready()函数结合使用准备函数检查是否有任何内容要“读入”,因此,如果没有输入,则不会卡在“ readLine”上。

On the Server: 在服务器上:

-Like i said earlier, I'd change back to using a normal Array. -和我之前说的一样,我将改回使用普通数组。

-Your server will still get stuck on .accept(). -您的服务器仍将卡在.accept()上。 As such, you will never be able to read input from the clients except once after each connection. 这样,您将永远无法读取来自客户端的输入,除非在每次连接之后都执行一次。 You can use a thread to listen instead, and it will still work. 您可以改用线程监听,它仍然可以正常工作。

eg: (this code goes with the code that's in the link i attached (also your question), put it before the while loop of your server) 例如:(此代码与我附加的链接(也是您的问题)中的代码一起,将其放在服务器的while循环之前)

// 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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM