我有一台服务器,有2个客户端通过TCP连接到它。 这些客户端不断向服务器发送信息。 这是一个代理服务器,并中继从客户端收到的消息。 但它必须交替传递消息。即来自客户端A的消息,然后是来自客户端B的消息,然后再来自A然后是B等等。 我可以通过检查消息来自哪里来实现,然后交替中继消息并忽略来自同一客户端的连续消息。
但是,如果任何客户端断开连接或未发送消息,我也不希望服务器陷入困境。 如果发生这种情况,代理将继续等待来自客户端的某些消息,该消息现在已断开连接(或由于某种原因未发送消息)。在这种情况下,我希望服务器从唯一连接的客户端中继消息。
相反,我想是否有可能这样的事情。如果我从同一个客户端获得2个连续的消息,我想检查是否读取了另一个客户端给我发送消息。 我的问题是,是否有可能从其他客户端的套接字检查是否有缓冲消息并准备发送。 在这种情况下,可以忽略来自同一客户端的连续消息,而是首先从其他客户端发送消息。 (我已经查过了。)
这可能吗?希望我已经清楚地提出了这个问题。
由于
答案 0 :(得分:2)
我正在阅读这个问题:
你有:
1台服务器
2个客户
您的服务器从客户端1和2获取消息并转发它们。
客户端是不同的生产者,这意味着他们发送的消息可能会有所不同。您想要的是来自客户端的消息可以从服务器中以可选方式发送出去,但如果客户端丢弃则不会“等待”。
在这种情况下,我建议你的服务器中有两个队列(client1queue和client2queue)。
您必须从两个单独的线程中读取套接字,并在收到消息时将其添加到相应的队列中。 client1Socket - > client1queue client2Socket - > client2queue
然后,在第三个线程中,让服务器转发消息,交替从client1queue和client2queue中提取这些消息。
如果队列为空,要解决“不等待”的问题,只需跳过队列“转”即可。这可确保以最快的速率发送所有消息,同时仍然可以获取所有消息。缺点是只有在准备好发送消息时它才会交替。当然,您可以让它等待X金额以查看是否有消息来自另一个队列,但我不明白为什么如果系统应该工作而不管客户端状态如何。
答案 1 :(得分:1)
您可以使用setSoTimeout()方法将套接字上的读取超时设置为较短(例如,可能是等待每个客户端的时间或其他时间);这样,当你从客户端A获得第二条消息时,你可以从客户端B的套接字读取(),如果你得到一个SocketTimeoutException,那么你可以处理A的消息。
但是,您必须修改当前代码以捕获每次从套接字读取时可能获得的任何SocketTimeoutExceptions。
答案 2 :(得分:1)
问题是:要测试客户端是否被删除,您必须对套接字进行读取,但是,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?!
}
}
答案 3 :(得分:0)
由于我将在下面解释的原因,我只是将有趣的事件视为消息 - 或消息的一部分 - 是否已经到达您的服务器。所以:
你可能想要在套接字上设置超时,正如另一张海报所暗示的那样,尽管有这种线程模型,我认为这不是至关重要的 - 它实际上取决于你想要的策略强加
您向客户询问的其他建议是可行的,但这可能不是您真正想要的解决方案。你打开另一个通道给客户询问“你刚刚发送了一些数据”。但是,如果客户已经拥有了,而你却没有,那么总的来说,有些东西已经错了,目前尚不清楚这些知识是否会对你有所帮助。或者它可能会说“不”,然后就在那一刻发送数据。并且客户的另一个渠道会工作吗?如果客户说它发送了什么,你怎么知道它是否即将到来或“迷路”并且永远不会到达......?
答案 4 :(得分:0)
我想这样做的方式是: 如果我从客户端A获得2个连续消息,我将获得连接到客户端B的socket的inputStream。然后调用inputStream上的available()方法,看看是否有任何可用的字节可供读取。 如果有要读取的字节,则从客户端B的套接字读取。否则从客户端A中继消息(第二个连续消息)。
对此有任何意见。
答案 5 :(得分:0)
如果客户端A在客户端B发送消息之前发送第二条消息,您是否打印出来自客户端A的第二条消息?在这种情况下,它根本不是交替的,你只是按照它们到达的顺序打印到达的消息。或者,您想稍等一下,看看是否有消息从客户端B到达?
我认为无论哪种方式,除了“主”线程之外,你还需要为每个客户端创建一个单独的线程。每个客户端线程不断尝试从其各自的客户端读取消息,该消息将阻塞直到它收到消息。当套接字线程收到消息时,它会将其放在SynchronousQueue
上,其中所有三个线程都有一个实例。此put
操作将一直阻止,直到主线程调用take
上的SynchronousQueue
。
主线程可以简单地循环并在take
上调用SynchronousQueue
。这将阻塞,直到其中一个客户端线程调用put
。
如果您要执行交替消息,则可以使用两个SynchronousQueue
,每个客户端一个。你想在你的主循环中引入一些延迟,让两个客户都有机会在转发之前写出他们的消息。
答案 6 :(得分:0)
我会查找可用()方法的javadoc。它没有按照你的想法做到。
答案 7 :(得分:0)
您有两个不同的问题:
1)从多个客户端读取消息,不会阻塞。
2)以合理的方式将消息写入输出。
如果为每个客户端套接字使用单独的线程,则可以解决第一个问题。如果您有许多客户端,您可以考虑使用SocketChannel和Selector来使用非阻塞io。
请记住,TCP / IP流可能会在每次读取操作中提供多条或部分消息,具体取决于网络和套接字选项,因此您必须处理这些消息。
第二个问题可以通过为每个客户端保留队列或者使用优先级队列来解决,并根据客户端的活动为每条消息附加优先级。