2

我想要这个设置:

  • 服务器托管 TCP 套接字服务器
  • 通过 TCP 连接的多个客户端(保持连接打开)

然后我想从服务器向客户端发起一条消息。我不知道如何做到这一点,并且同时有多个客户端会话。我读过的技术涉及服务器侦听端口,当它接收到来自客户端的通信时,它会启动一个新线程来处理和处理它,然后它会返回侦听端口以获取另一个客户端的下一个请求.
那么,我将如何利用它并向在其中一个线程上运行的客户端发送消息?

如果您有兴趣,我的实际使用场景如下。最终目标就像是远程控制您的文件系统将文件上传到服务器。- 每个客户端都有一个运行在系统托盘中的 Java 后台应用程序,该应用程序连接到服务器 - 服务器托管连接,还托管 RESTFul Web 服务以启动通信 - 移动设备通过 RESTFul Web 服务连接到服务器以请求有关客户端文件系统的信息。所以它可以向下钻取并找到一个文件,然后单击并将文件上传到服务器。这里的想法是移动用户需要在离开办公室时通过移动设备将文件从桌面上传到服务器。(这是定制产品,所以不能使用第三方应用程序_

PS:我一直在这里查看简单的客户端-服务器聊天程序:http ://way2java.com/networking/chat-program-two-way-communication/

4

2 回答 2

0

您希望服务器始终在指定端口上侦听。一旦服务器注意到该端口上的传入连接,您应该创建一个新线程来处理该客户端和服务器之间的通信,而主线程继续侦听其他传入连接。这样,您可以将多个客户端连接到一个服务器。像这样:

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

GlobalFlags 是控制监听过程的变量,并不是真正必要的。你可以做一段时间 True ,然后一直听下去。

在我的项目中,我有一个主服务器控制器,它的侦听器在线程中运行。控制器控制 GlobalFlags。我敢肯定,除了使用全局标志之外,还有一种更好的方法来进行线程间通信,但对我来说,这是当时最简单的方法。

ServerThread 应该一直循环在向客户端发送输出和从客户端接收输入之间切换。像这样:

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.
}

在客户端,您有一个线程通过类似的循环运行,从服务器接收输入,然后将输出发送到服务器。

在此示例中,processInput 是用于处理客户端输入的函数。如果您希望服务器启动联系,您可以让服务器在侦听输入之前向输出流发送一些内容,并让客户端先侦听。

我已经从我自己的一个项目中提取了这个例子,并且 this.socket.setTcpNoDelay(true) 应该使这个过程更快。参考这里:http ://www.rgagnon.com/javadetails/java-0294.html

“java.net.Socket.setTcpNoDelay() 用于启用/禁用 TCP_NODELAY,该 TCP_NODELAY 禁用/启用 Nagle 算法。Nagle 算法尝试通过最小化发送的段数来节省带宽。当应用程序希望减少网络延迟并提高性能时, 他们可以禁用 Nagle 的算法(即启用 TCP_NODELAY)。数据将更早发送,但会增加带宽消耗。Nagle 的算法在 RFC 896 中有描述。

您可以使用 java.net.Socket.getTcpNoDelay() 获得当前的“TCP_NODELAY”设置”


因此,要将消息发送到特定客户端,您可以在创建时将所有线程放在 ArrayList 中,这样您就可以跟踪所有当前连接的客户端。您可以让 processInput 方法停止并轮询队列/变量,直到另一个类将要发送的消息放入队列/变量中。所以如何获得类的句柄取决于你对 processInput 的实现。您可以给每个线程一个 ID(这是我在我的项目中所做的),并且可能让 processInput 方法在 index=ID 处轮询一个 ArrayList。然后要将输出发送到客户端,您必须将变量设置为 index=ID。

这种方法对我个人来说似乎有点笨拙,但我不确定我该怎么做。您可能会使用队列并让 processInput 将输入写入其队列,然后等待另一个类读取它并将其响应放入队列中。但我个人从未在 java 中使用过队列,所以你应该自己阅读。

于 2013-02-19T15:06:43.860 回答
0

据我所知 1) 服务器托管 TCP 套接字服务器 - 可能 2) 通过 TCP 连接的多个客户端 - 可能 3) 然后我想从服务器向客户端发起一条消息 - 不可能。客户端必须启动连接创建,然后服务器可能能够向您发送数据包。示例:您需要在浏览器上打开 Facebook 网站,Facebook 服务器无法自行决定将其页面发送到您的 PC,因为您的 PC 没有静态 IP 地址,而且如果 Facebook 假设编写代码来启动与您的 PC 的连接,那么它就像您的 PC 是服务器和 Facebook 网站/服务器充当客户端一样好。

于 2016-10-10T07:29:09.287 回答