简体   繁体   English

处理多个客户端的流?

[英]Handle streams with multiple clients?

basically what i want to do is develop a chat program(something between an instant messenger and IRC) to improve my java skills. 基本上我想做的是开发一个聊天程序(介于即时通讯程序和IRC之间)来提高我的Java技能。

But I ran into 1 big problem so far: I have no idea how to set up streams properly if there is more than one client. 但是到目前为止,我遇到了一个大问题:我不知道如果有多个客户端,如何正确设置流。 1:1 chat between the client and the server works easily, but I just don't know what todo so more than 1 client can be with the server in the same chat. 客户端与服务器之间的1:1聊天很容易进行,但是我不知道该怎么办,因此同一聊天中服务器可以与1个以上的客户端进行聊天。

This is what I got, but I doubt its going to be very helpful, since it is just 1 permanent stream to and from the server. 这就是我得到的,但是我怀疑它会很有帮助,因为它只是往返于服务器的1个永久流。

private void connect() throws IOException {
        showMessage("Trying to connect \n");
        connection = new Socket(InetAddress.getByName(serverIP),27499);
        showMessage("connected to "+connection.getInetAddress().getHostName());

    }

    private void streams() throws IOException{
        output = new ObjectOutputStream(connection.getOutputStream());
        output.flush();
        input = new ObjectInputStream(connection.getInputStream());
        showMessage("\n streams working");

    }

To read from multiple streams in one program, you're going to have to use multithreading. 要从一个程序中读取多个流,您将必须使用多线程。 Because reading from streams is synchronous, you'll need to read from one stream for each thread. 因为从流中读取是同步的,所以您需要为每个线程从一个流中读取。 See the java tutorial on threads for more info on multithreading. 有关多线程的更多信息,请参见线程Java教程

Made something like that a few months back. 几个月前做了类似的事情。 basically I used a separate ServerSocket and Thread per client server side. 基本上,我在每个客户端服务器端使用了单独的ServerSocketThread When client connects you register that port's input and output streams to a fixed pool and block until input is sent. 当客户端连接时,您将该端口的输入和输出流注册到固定池中并阻塞,直到发送输入为止。 then you copy the input to each of the other clients and send. 然后将输入复制到其他每个客户端并发送。 here is a basic program run from command line: Server code: 这是从命令行运行的基本程序:服务器代码:

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;

    public class ChatServer {

        static int PORT_NUMBER = 2012;

        public static void main(String[] args) throws IOException {


            while (true) {
                try (ServerSocket ss = new ServerSocket(PORT_NUMBER)) {
                    System.out.println("Server waiting @" + ss.getInetAddress());
                    Socket s = ss.accept();
                    System.out.println("connection from:" + s.getInetAddress());

                    new Worker(s).start();
                }
            }

        }

        static class Worker extends Thread {

            final static  ArrayList<PrintStream> os = new ArrayList(10);
            Socket clientSocket;
            BufferedReader fromClient;

            public Worker(Socket clientSocket) throws IOException {
                this.clientSocket = clientSocket;
                PrintStream toClient=new PrintStream(new BufferedOutputStream(this.clientSocket.getOutputStream()));
                toClient.println("connected to server");
                os.add(toClient);
                fromClient = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));

            }
            @Override
            public void run() {

                while (true) {
                    try {
                        String message = fromClient.readLine();
                        synchronized (os) {


                            for (PrintStream toClient : os) {
                                toClient.println(message);
                                toClient.flush();
                            }
                        }

                    } catch (IOException ex) {
                        //user discnnected
                        try {
                            clientSocket.close();
                        } catch (IOException ex1) {

                        }
                    }

                }
            }
        }

}

Client code: 客户代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class Client {

    public static void main(String[] args) throws IOException {

        final BufferedReader fromUser = new BufferedReader(new InputStreamReader(System.in));
        PrintStream toUser = System.out;
        BufferedReader fromServer;
        final PrintStream toServer;
        Socket s = null;

        System.out.println("Server IP Address?");


        String host;
        String port = "";


        host = fromUser.readLine();

        System.out.println("Server Port Number?");

        port = fromUser.readLine();

        s = new Socket(host, Integer.valueOf(port));

        int read;
        char[] buffer = new char[1024];


        fromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
        toServer = new PrintStream(s.getOutputStream());
        new Thread() {

            @Override
            public void run() {
                while (true) {
                    try {
                        toServer.println(">>>" + fromUser.readLine());

                        toServer.flush();
                    } catch (IOException ex) {
                        System.err.println(ex);
                    }
                }
            }
        }.start();
        while (true) {
            while ((read = fromServer.read(buffer)) != -1) {
                toUser.print(String.valueOf(buffer, 0, read));
            }
            toUser.flush();

        }
    }
}

I've done this several times with ServerSocket(int port) and Socket ServerSocket.accept() . 我已经使用ServerSocket(int port)Socket ServerSocket.accept()做了几次。 This can be pretty simple by having it listen to the one port you want your chat server client listening on. 通过让它监听您希望聊天服务器客户端监听的一个端口,这可以非常简单。 The main thread will block waiting for the next client to connect, then return the Socket object to that specific client. 主线程将阻止等待下一个客户端连接,然后将Socket对象返回给该特定客户端。 Usually you'll want to put them in a list to generically handle n-number of clients. 通常,您需要将它们放在一个列表中,以处理n个客户。

And, yes, you will probably want to make sure each Socket is in a different thread, but that's entirely up to you as the programmer. 而且,是的,您可能要确保每个Socket处于不同的线程中,但这完全取决于程序员。

Remember, there is no need to re-direct to another port on the server, by virtue of the client using a different source port, the unique 5-tuple (SrcIP, SrcPort, DstIP, DstPort, TCP/UDP/other IP protocol) will allow the one server port to be re-used. 请记住,由于客户端使用不同的源端口(唯一的5元组(SrcIP,SrcPort,DstIP,DstIP,DstPort,TCP / UDP /其他IP协议)),因此无需重定向到服务器上的另一个端口将允许重用一个服务器端口。 Hence why we all use stackoverflow.com port 80. 因此,为什么我们都使用stackoverflow.com端口80。

Happy Coding. 编码愉快。

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

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