代码之家  ›  专栏  ›  技术社区  ›  Anand

Java网络编程。关于插座的问题

  •  3
  • Anand  · 技术社区  · 16 年前

    我有一个服务器,有两个客户端通过TCP连接到它。 这些客户机不断地向服务器发送信息。 这是一个代理服务器,并中继它从客户机接收的消息。 但它必须交替地传递信息。也就是说,先从客户机A发送消息,然后从客户机B发送消息,然后再从客户机A发送消息,然后再从客户机B发送消息,依此类推。 我可以通过检查消息来自何处,然后交替地中继消息,忽略来自同一客户机的连续消息来实现这一点。

    但是,我也不希望服务器在任何客户机断开连接或不发送消息时陷入困境。 如果发生这种情况,代理将继续永远等待来自客户机的某些消息,而该消息现在已断开连接(或者出于某种原因不发送消息)。在这种情况下,我希望服务器从唯一连接的客户机中继消息。

    相反,我在想这样的事情是否可行。如果我从同一个客户机连续收到两条消息,我想检查是否读取了另一个客户机,以便向我发送消息。 我的问题是,是否可以从另一个客户机的套接字检查是否有消息被缓冲并准备发送。 在这种情况下,可以忽略来自同一个客户机的连续消息,而是首先从另一个客户机发送消息。(我已经检查过了。)

    这有可能吗?希望我问得清楚。

    谢谢

    8 回复  |  直到 16 年前
        1
  •  2
  •   Alex    16 年前

    我这样解读这个问题:

    你有:

    1服务器

    2客户

    服务器从客户机1和2接收消息并转发它们。

    客户机是不同的生产者,这意味着他们发送的消息可能不同。您需要的是客户机的消息交替地从您的服务器发送出去,但如果客户机已丢失,则不要“等待”。

    在这个场景中,我建议在服务器中有两个队列(client1queue和client2queue)。

    您必须从两个独立线程中的套接字中读取消息,当消息传入时,将其添加到相应的队列中。 客户1库存->客户1队列 client2socket->客户机2队列

    然后,在第三个线程中,让服务器转发消息,交替地从client1queue和client2queue中提取这些消息。

    如果队列是空的,那么要解决“不等待”的问题,只需跳过队列的“转弯”即可。这样可以确保以尽可能快的速度发送所有消息,同时仍能接收所有消息。缺点是,只有当消息准备好发送时,它才交替发送。当然,您可以让它等待x amount,以查看是否有消息出现在另一个队列中,但是我不明白如果系统应该工作而不管客户机状态如何,您为什么要这样做。

        2
  •  1
  •   Chochos    16 年前

    您可以使用setsoTimeout()方法将套接字上的读取超时设置为较短的时间(例如,可能是一秒钟,也可以是您希望等待每个客户机的任何时间);这样,当您从客户机A获取第二条消息时,您只需从客户机B的套接字读取(),如果您获得了socketTimeout异常,则可以处理A的消息。

    但是,您必须修改当前代码,以便在从套接字读取时捕获任何socketTimeoutExceptions。

        3
  •  1
  •   Alex    16 年前

    问题是:为了测试客户端是否被丢弃,必须在套接字上读取,但是,Java的Socket类不允许在套接字上异步读取。因此,如果在没有设置超时的情况下进行读取,并且没有发送任何内容,那么应用程序将扣押进程,等待读取某些内容。

    所以,在实例化了套接字之后,您需要使用:socket.setsoTimeout(int)来给它一段时间,让它在超时之前“等待”。接下来会发生的事情是,每次尝试阅读时都会超时,如果阅读返回-1,您知道客户机已断开连接。

        Socket clientSocket=theServerSocket.accept();
        clientSocket.setSoTimeout(1);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    
    while(serverIsRunning){
           try{
               if(bufferedReader.read()==-1){
                      logger.info("The server has disconnected!");
                      //Do whatever clean up you need, ect
               }
           }
           catch (SocketTimeoutException e){
               //the server is still running, yay?!
           }
    }
    
        4
  •  0
  •   Neil Coffey    16 年前

    出于我将在下面解释的原因,我将把这个有趣的事件视为消息(或消息的一部分)是否已经到达您的服务器。所以:

    • 让一个线程从每个客户机读取数据,就像您可能得到的那样
    • 另一个 执行消息排序规则的线程
    • 当:新消息的第一部分到达时,让客户机线程向消息排序规则线程发出信号;当来自客户机的消息完成时(此时,它将实际消息传递给排序规则线程)
    • 然后,如果您的排序规则线程没有“消息的第一部分已到达”的初始信号,只需将其视为“客户机尚未准备好发送消息”。

    可能 想要像另一个海报所建议的那样在套接字上设置超时,尽管使用这个线程模型,我认为这并不重要——它实际上取决于您想要实施什么策略。

    你询问客户的另一个建议是可能的,但这可能不是你真正想要的解决方案。你打开另一个通道,问客户“你刚刚发送了一些数据吗”。但是,如果客户有,而你没有得到,那么一般来说,有些事情已经出了问题,不清楚这些知识是否会对你有很大帮助。或者它可能会说“不”,然后就在此时发送数据。另一个到客户的渠道会起作用吗?如果客户说它发送了一些东西,你怎么知道它是即将到达,还是“迷路了”,永远不会到达……?

        5
  •  0
  •   Anand    16 年前

    我想这样做的方式是: 如果我从客户机A连续收到2条消息,我将得到连接到客户机B的套接字的inputstream。然后调用inputstream上的available()方法,查看是否有字节可供读取。 如果要读取字节,则从客户机B的套接字读取。否则,从客户机A中继消息(第二个连续消息)。

    对此有何评论?

        6
  •  0
  •   Sam Barnum    16 年前

    如果客户机A在客户机B发送消息之前发送第二条消息,您是否打印出客户机A的第二条消息?在这种情况下,它根本就不是交替的,你只需要打印任何按消息到达顺序到达的消息。或者,您想稍等一下,看看是否有来自客户机B的消息到达?

    不管怎样,您都需要为每个客户机分别运行一个线程,除了“主”线程之外。每个客户机线程不断地尝试从其各自的客户机读取一条消息,直到它收到一条消息为止。当一个套接字线程接收到一条消息时,它将它放到 SynchronousQueue ,其中三个线程都有一个实例。这个 put 操作将阻塞,直到主线程调用 take 同步队列 .

    主线程可以简单地循环和调用 同步队列 . 这将阻塞,直到其中一个客户端线程调用 .

    如果你想交换信息,你可以有两个 同步队列 相反,每个客户一个。您需要在主循环中引入一些延迟,以便给两个客户机在转发消息之前都有机会编写它们的消息。

        7
  •  0
  •   Dan.StackOverflow    16 年前

    我将在javadoc中查找available()方法。它不像你想象的那样。

        8
  •  0
  •   KarlP    16 年前

    您有两个单独的问题:

    1)从多个客户端读取消息,不阻塞。

    2)以公平的方式将消息写入输出。

    如果为每个客户机套接字使用单独的线程,则可以解决第一个问题。如果您有许多客户机,可以考虑使用socketchannel和选择器来使用非阻塞IO。

    请记住,根据网络和套接字选项,TCP/IP流可能会在每个读取操作中传递几个或只传递部分消息,因此必须注意这一点。

    第二个问题可以通过为每个客户机保留一个队列或者使用优先级队列来解决,并根据客户机的活动性为每个消息附加优先级。