开发基于TCP / IP的消息客户端的建议

时间:2011-02-18 16:23:55

标签: c# java tcpclient

我有一个控制电话系统的服务器端协议,我已经实现了一个与之通信的客户端库,现在正在生产中,但是我现在的系统存在一些问题,所以我正在考虑重写它。

我的客户端库目前是用Java编写的,但我想用C#和Java重写它,以允许不同的客户端访问同一个后端。

以关键字开头的消息包含多个字节的元数据,然后是一些数据。消息始终以消息字符结尾终止。

客户端和服务器之间的通信是双工的,通常采取来自客户端的请求的形式,该请求会引发服务器的多个响应,但可以是通知。 消息标记为:

C:命令

P:待定(服务器仍在处理请求)

D:数据数据作为对

的回应

R:回复

B:忙(服务器太忙,无法处理响应)

N:通知

我当前的架构已经解析了每个消息并生成了一个线程来处理它,但是我发现一些Notifications被无序处理,这导致我一些麻烦,因为它们必须以相同的顺序处理他们到了。

双工消息倾向于采用以下消息格式: 客户 - >服务器:命令 服务器 - >客户:待定(可选) 服务器 - >客户:数据(可选) 服务器 - >客户端:响应(消息数据中的第2个条目表示这是否是错误)

我一直在使用该协议超过一年,我从未见过这是一个忙碌的信息,但这并不意味着它们不会发生。

服务器还可以向客户端发送通知,并且有一些响应消息由服务器上的事件自动触发,因此在没有发出相应命令的情况下发送它们。

某些通知消息将作为消息序列的一部分到达,例如:

NotificationName M00001 NotificationName M00001 NotificationName M00000

字符串M0000X意味着要有更多数据要出现,或者这是消息的结尾。

目前tcp客户端相当愚蠢,它只是产生一个线程,通知订阅者的事件已收到消息,该事件特定于消息关键字和消息类型(So数据,响应和通知)单独处理)这对于数据和响应消息非常有效,但由于它们似乎以快速顺序到达而导致通知消息失败,并且竞争条件有时似乎导致在具有数据的消息结束之前处理消息结束被处理,导致丢失的消息数据。

鉴于这个系统工作原理的描述非常糟糕,您将如何编写客户端传输代码?

元数据没有消息编号,我无法控制供应商提供的底层协议。

3 个答案:

答案 0 :(得分:1)

我只推荐基于Java的解决方案。

我会使用一些已经成熟的传输框架。 “一些”我的意思是我到目前为止唯一使用过的 - Apache MINA。但是,它很有效,而且非常灵活。

关于无序处理消息 - 对于必须按照接收顺序生成的消息,您可以构建队列并将此类消息放入队列中。
要限制队列数,您可以实例化4个队列,并将传入消息路由到特定队列,具体取决于消息排序部分的散列的最后2位(indeces 0-3)(例如, message_id包含在消息中。)

如果您有更具体的问题,我可以适当更新我的答案。

答案 1 :(得分:1)

必须按照接收消息的顺序处理消息的要求几乎强制生成器/消费者设计,其中侦听器从客户端获取请求,解析它们,然后将解析的请求放入队列中。一个单独的线程(使用者)按顺序从队列中获取每条消息,对其进行处理,并向客户端发送响应。

或者,使用者可以将结果放入队列,以便另一个线程(可能是侦听器线程?)可以将结果发送到客户端。在这种情况下,您将拥有两个生产者/消费者关系:

Listener -> event queue -> processing thread -> output queue -> output thread

在.NET中,使用BlockingCollection来处理队列非常容易实现。我不知道Java中是否有类似的内容。

多消息请求的可能性使事情变得复杂,因为在将整个事物放入队列之前,似乎监听器必须缓冲消息,直到请求的最后部分进入。

对我来说,生产者/消费者设计的优点在于它强制程序的不同部分之间难以分离,使每个部分更容易调试并最小化共享状态导致问题的可能性。这里唯一稍微复杂的部分是你必须包含连接(套接字或其他)作为在队列中共享的消息的一部分,以便输出线程知道在哪里发送响应。

我不清楚您是否必须按照收到的顺序处理所有邮件,或者您是否只需按正确的顺序处理任何特定客户的邮件。例如,如果您有:

Client 1 message A
Client 1 message B
Client 2 message A

在处理来自客户端1的第二条消息之前,是否可以处理来自客户端2的第一条消息?如果是这样,那么您可以通过使用逻辑上多个队列来增加吞吐量 - 每个客户端一个。您的“消费者”然后变成多个线程。您只需要确保每个客户端只能处理一条消息。

答案 2 :(得分:1)

每个客户端都有一个线程可以进行解析和处理。这样,处理将按其发送/到达的顺序进行。

如您所述,任务无法安全并行执行。在不同的线程中执行解析和处理可能会增加您可能节省的开销。

如果您的处理相对简单并且不依赖于外部系统,则单个线程应该能够每秒处理1K到20K的消息。

您是否还有其他想要解决的问题?