我目前正在制作一个客户端 - 服务器应用程序,主要用于对服务器进行过程调用并等待数据包响应。
但是我想将服务器“推送”消息发送给客户端(在一个自发的时间),但如果消息在客户端侦听另一个数据包响应时到达,这似乎是一个问题。
有没有办法通过同一个套接字实例将套接字拆分为2个唯一的通道流?或者创建一个只监听传入连接并将它们分派到队列的客户端线程会更好吗?
使用双向客户端 - 服务器连接时,有哪些常见的模式和做法? (溪流自发发生)
对于提醒我正在使用Java Socket,ObjectInputStream和ObjectOutputstream。我没有使用Java RMI。
答案 0 :(得分:1)
因此,在学习网络时遇到的一件事就是失去同步。例如,当您“硬编码”某组客户端 - 服务器交互时,会发生这种情况;
server sends 2 byte status code
client receives 2 byte status code
client responds with 4 byte operation code
如果由于某种原因导致错误导致此交互的任何部分不能按照需要精确发生,则程序的 rest 会失败,因为所有网络交互现在都不同步。客户端可能会读取它认为代表字符串的一组字节,当服务器真正发送一个int时,依此类推。最糟糕的是,您可能会发现主网络线程死锁,因为客户端和服务器都在同时等待输入。
对于一个更大的项目,当然存在错误,如果你用这种风格编码,这个 会发生很多事情。出于这个原因,我们有一个叫做中间件的东西。
一个非常常见且灵活的中间件范例是TLV Message Protocol。您将实现一些简单的类(在半java-pseudocode中);
TLVMessage
int type;
byte[] value;
TLVPusher implements Runnable
OutputStream out;
Queue<TLVMessage> messages;
run() {
while(true) {
//poll and write front of queue to out (INCLUDING value.length!)
}
}
TLVReader implements Runnable
InputStream in;
Queue<TLVMessage> messages;
run() {
while(true) {
//read message from in and add to queue
}
}
现在,您在客户端上运行了两个线程,并在服务器上运行了两个线程。每个目标都有自己的Pusher
和Reader
。需要注意的重要一点是,因为您将长度字段写入输出流,读取器总是知道需要读取多少字节。因此,即使一条消息被错误地序列化,其长度仍然正确,并且始终从第一个字节到最后一个字节正确读取下一条消息。这样,您的程序永远不会失去同步。
您只需将TLVMessage
个对象添加到pusher.queue
,它们就会到达套接字另一端的reader.queue
。然后,您可以通过reader.messages.size()
字段处理消息(在另一个,第三个,监视type
的线程中)。
您无需担心事情发生的顺序,您有一个强大的机制,可以在两个方向上在客户端和服务器之间传递消息。你已经抽出了繁琐的网络资料,并且可以继续编码。
当然,libraries可以为您完成所有这些工作,但在我看来,总是值得理解 和为什么。< / p>
答案 1 :(得分:0)