简体   繁体   English

服务器启动的客户端-服务器通信

[英]Client-Server communication where Server initiates

I would like to have this setup: 我想进行以下设置:

  • Server hosting TCP socket server 托管TCP套接字服务器的服务器
  • Multiple clients connected over TCP (keeping connection open) 多个客户端通过TCP连接(保持连接打开)

Then I would like to initiate a message from the Server to the client. 然后,我想启动从服务器到客户端的消息。 I can't figure out how to do this, and have multiple client sessions at the same time. 我不知道如何执行此操作,并且无法同时进行多个客户端会话。 Techniques I've read involve the Server listening on a port, and when it receives communicate from a client, it launches a new thread to handle and process that, and then it goes back to listening on the port for the next request of another client. 我读过的技术涉及服务器侦听端口,并且当它接收到来自客户端的通信时,它将启动一个新线程来处理和处理该线程,然后返回侦听该端口上的另一个客户端的下一个请求。 。
So, then how would I tap into that and send a message to a client running on one of those threads? 那么,我将如何利用它并向运行在其中一个线程上的客户端发送消息?

My actual usage scenario if you are interested is below. 如果您有兴趣,我的实际使用情况如下。 Final goal is like a remote control for your file system to upload files to the server. 最终目标就像是文件系统的远程控制,用于将文件上传到服务器。 - Each client has a java background application running in the system tray that connects to the server - Server hosts connections, and also hosts a RESTFul webservice to initiate communication - Mobile device connects to Server over RESTFul webservices to request informatino about the client's filesystem. -每个客户端都在系统托盘中运行一个Java后台应用程序,该应用程序连接到服务器-服务器托管连接,还承载RESTFul Web服务以启动通信-移动设备通过RESTFul Web服务连接到Server以请求有关客户端文件系统的信息。 So it can drill down and find a file, then click and have the file uploaded to the server. 因此,它可以向下钻取并找到文件,然后单击并将文件上传到服务器。 The idea here is mobile users needing to upload files from their desktop to the server while away from their office on a mobile device. 这里的想法是移动用户需要在离开移动设备上的办公室时将文件从其桌面上传到服务器。 (and this is for custom product, so can't use a third-party app_ (这是针对自定义产品的,因此不能使用第三方app_

PS: I've been looking at the simple Client-Server chat program here: http://way2java.com/networking/chat-program-two-way-communication/ PS:我一直在这里查看简单的Client-Server聊天程序: http : //way2java.com/networking/chat-program-two-way-communication/

You want to have a server listening at all times on a specified port. 您希望服务器始终在指定端口上进行侦听。 Once the server notices an incoming connection on that port you should create a new Thread to handle the communication between that client and the server, while the main thread keeps on listening for other incoming connections. 服务器注意到该端口上有传入连接后,您应该创建一个新线程来处理该客户端与服务器之间的通信,而主线程则继续侦听其他传入连接。 This way you can have multiple clients connected to one server. 这样,您可以将多个客户端连接到一台服务器。 Like so: 像这样:

private void listen() throws IOException {
    serverSocket = new ServerSocket(port)
    while (GlobalFlags.listening) {
        new ServerThread(serverSocket.accept();
        if (GlobalFlags.exit) {
            serverSocket.close();
            break;
        }
    }
}

Where the GlobalFlags are variables to control the listening process and are not really necessary. GlobalFlags是控制侦听过程的变量,并不是真正必需的。 You could do a while True and just keep listening for ever and ever. 您可以做一会儿True,然后一直听下去。

In my project I have a main server controller which had listeners running in Threads. 在我的项目中,我有一个主服务器控制器,该服务器的侦听器在线程中运行。 The controller controlled the GlobalFlags. 控制器控制GlobalFlags。 I'm sure instead of using global flags there is a better way to do inter thread communication but for me this was the simplest at the time. 我敢肯定,除了使用全局标志之外,还有一种更好的进行线程间通信的方法,但是对我来说,这是当时最简单的方法。

The ServerThread should be looping all the time switching between sending output to the client and receiving input from the client. ServerThread应该在所有时间之间循环,在将输出发送到客户端和从客户端接收输入之间。 Like so: 像这样:

ServerThread(Socket socket) {
    super("GameServerThread");
    this.socket = socket;
    try {
        this.socket.setTcpNoDelay(true);
    } catch (SocketException e) {
        // Error handling
    }
    this.terminate = false;
}

@Override
public void run() {        
    try {
        out = new PrintWriter(socket.getOutputStream(), true);
        in = new BufferedReader(
             new InputStreamReader(
             socket.getInputStream()));

        String inputLine, outputLine;

        while ((inputLine = in.readLine()) != null) {
                outputLine = processInput(inputLine);
                out.println(outputLine);
                if (terminate) {
                    break;
                }
            }
        }
        out.close();
        in.close();
        socket.close();

    } catch (Exception e) {
        // Error handling, should not use Exception but handle all exceptions by themselves.
}

On the client side you have a thread running through a similar loop, receiving input from the server and then sending output to the server. 在客户端,您有一个线程通过相似的循环运行,从服务器接收输入,然后将输出发送到服务器。

In this example processInput is the function used to process the client's input. 在此示例中,processInput是用于处理客户端输入的函数。 If you want the server to initiate contact you can make the server send something to the outputstream before listening for input and make the client listen first. 如果希望服务器启动联系,则可以使服务器在侦听输入之前向输出流发送一些内容,并使客户端首先侦听。

I have extracted this example from one of my own projects and the this.socket.setTcpNoDelay(true) is supposed to make the process faster. 我从我自己的项目之一中提取了此示例,并且this.socket.setTcpNoDelay(true)应该可以使过程更快。 Reference here: http://www.rgagnon.com/javadetails/java-0294.html 此处参考: http : //www.rgagnon.com/javadetails/java-0294.html

"java.net.Socket.setTcpNoDelay() is used to enable/disable TCP_NODELAY which disable/enable Nagle's algorithm. Nagle's algorithm try to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase in bandwidth consumption. The Nagle's algorithm is described in RFC 896. “ java.net.Socket.setTcpNoDelay()用于启用/禁用Nagle算法的TCP_NODELAY。Nagle算法尝试通过最小化发送的段数来节省带宽。当应用程序希望减少网络延迟并提高性能时,他们可以停用Nagle的算法(即启用TCP_NODELAY)。数据将更早发送,但会增加带宽消耗; RFC 896中对Nagle的算法进行了说明。

You get the current "TCP_NODELAY" setting with java.net.Socket.getTcpNoDelay()" 您可以通过java.net.Socket.getTcpNoDelay()获得当前的“ TCP_NODELAY”设置


So to send a message to a specific client you could put all the threads upon creation in an ArrayList so you can keep track of all the currently connected clients. 因此,要向特定客户端发送消息,可以将创建后的所有线程放入ArrayList中,以便跟踪所有当前连接的客户端。 You can have the processInput method halt and polling a queue/variable until another class puts the message to be send in the queue/variable. 您可以使processInput方法暂停并轮询队列/变量,直到另一个类将要发送的消息放入队列/变量中为止。 So how to gain a handle on the class depends on your implementation of processInput. 因此,如何获得该类的句柄取决于processInput的实现。 You could give every thread an ID (which is what I did in my project) and maybe have the processInput method poll an ArrayList at index=ID. 您可以给每个线程一个ID(这就是我在项目中所做的事情),并且可能让processInput方法以index = ID轮询ArrayList。 Then to send output to the client you would have to set the variable at index=ID. 然后,要将输出发送到客户端,您必须将变量设置为index = ID。

This method seems kind of clunky to me personally but I'm not really sure how else I would do it. 就我个人而言,此方法似乎有些笨拙,但我不确定我还能怎么做。 You would probably use Queues and have processInput write the input to its Queue and then wait for another class to read it and put its response in the Queue. 您可能会使用Queues,并让processInput将输入内容写入其Queue,然后等待另一个类读取它并将其响应放入Queue中。 But I have personally never worked with Queues in java so you should read up on that yourself. 但是我个人从未在Java中使用Queues,因此您应该自己阅读。

In my knowledge 1) Server hosting TCP socket server -- Possible 2) Multiple clients connected over TCP -- Possible 3) Then I would like to initiate a message from the Server to the client -- Not Possible. 据我所知1)承载TCP套接字服务器的服务器-可能2)通过TCP连接的多个客户端-可能3)然后,我想启动一条从服务器到客户端的消息-不可能。 The Client has to initiate a connection creation, then the server might be able to send data packets to You. 客户端必须启动连接创建,然后服务器才能将数据包发送给您。 Example: You need to open Facebook website on your browser, Facebook server cannot decide to send its page to your PC on its own because your PC will not have a static IP address, and also if Facebook hypothetically writes code to initiate connection to Your PC, then it is as good as Your PC is the server and Facebook website/server acts as client. 示例:您需要在浏览器上打开Facebook网站,Facebook服务器无法决定将其页面单独发送到您的PC,因为您的PC没有静态IP地址,并且如果Facebook假设编写代码以启动与PC的连接,这与您的PC作为服务器以及Facebook网站/服务器充当客户端一样好。

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

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