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

时间:2013-02-19 14:56:30

标签: java sockets client-server

我想进行此设置:

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

然后我想从服务器向客户端发起一条消息。我无法弄清楚如何执行此操作,并同时拥有多个客户端会话。我读过的技术涉及服务器监听端口,当它接收到来自客户端的通信时,它启动一个新线程来处理和处理它,然后它返回监听端口以获取下一个请求另一个客户 那么,那么我将如何利用它并向在其中一个线程上运行的客户端发送消息?

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

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

2 个答案:

答案 0 :(得分:0)

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

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

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

在我的项目中,我有一个主服务器控制器,它有在线程中运行的监听器。控制器控制了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()用于启用/禁用禁用/启用Nagle算法的TCP_NODELAY。 Nagle的算法试图通过最小化发送的段数来节省带宽。当应用程序希望减少网络延迟并提高性能时,它们可以禁用Nagle的算法(即启用TCP_NODELAY)。数据将提前发送,代价是带宽消耗增加。 Nagle的算法在RFC 896中描述。

使用java.net.Socket.getTcpNoDelay()获取当前的“TCP_NODELAY”设置“


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

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

答案 1 :(得分:0)

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

相关问题