简体   繁体   中英

Suggestions for developing a TCP/IP based message client

I've got a server side protocol that controls a telephony system, I've already implemented a client library that communicates with it which is in production now, however there are some problems with the system I have at the moment, so I am considering re-writing it.

My client library is currently written in Java but I am thinking of re-writing it in both C# and Java to allow for different clients to have access to the same back end.

The messages start with a keyword have a number of bytes of meta data and then some data. The messages are always terminated by an end of message character.

Communication is duplex between the client and the server usually taking the form of a request from the Client which provokes several responses from the server, but can be notifications. The messages are marked as being on of:

C: Command

P: Pending (server is still handling the request)

D: Data data as a response to

R: Response

B: Busy (Server is too busy to handle response at the moment)

N: Notification

My current architecture has each message being parsed and a thread spawned to handle it, however I'm finding that some of the Notifications are processed out of order which is causing me some trouble as they have to be handled in the same order they arrive.

The duplex messages tend to take the following message format: Client -> Server: Command Server -> Client: Pending (Optional) Server -> Client: Data (optional) Server -> Client: Response (2nd entry in message data denotes whether this is an error or not)

I've been using the protocol for over a year and I've never seen the a busy message but that doesn't mean they don't happen.

The server can also send notifications to the client, and there are a few Response messages that are auto triggered by events on the server so they are sent without a corresponding Command being issued.

Some Notification Messages will arrive as part of sequence of messages, which are related for example:

NotificationName M00001 NotificationName M00001 NotificationName M00000

The string M0000X means that either there is more data to come or that this is the end of the messages.

At present the tcp client is fairly dumb it just spawns a thread that notifies an event on a subscriber that the message has been received, the event is specific to the message keyword and the type of message (So data,Responses and Notifications are handled separately) this works fairly effectively for Data and response messages, but falls over with the notification messages as they seem to arrive in rapid sequence and a race condition sometimes seems to cause the Message end to be processed before the ones that have the data are processed, leading to lost message data.

Given this really badly written description of how the system works how would you go about writing the client side transport code?

The meta data does not have a message number, and I have not control over the underlying protocol as it's provided by a vendor.

I can recommend only for Java-based solution.

I would use some already mature transport framework. By "some" I mean the only one I have worked with until now -- Apache MINA. However, it works and it's very flexible.

Regarding processing messages out-of-order -- for messages which must be produced in the order they were received you could build queues and put such messages into queues.
To limit number of queues, you could instantiate, say, 4 queues, and route incoming message to particular queue depending on the last 2 bits (indeces 0-3) of the hash of the ordering part of the message (for example, on the client_id contained in the message).

If you have more concrete questions, I can update my answer appropriately.

The requirement that messages must be processed in the order in which they're received almost forces a producer/consumer design, where the listener gets requests from the client, parses them, and then places the parsed request into a queue. A separate thread (the consumer) takes each message from the queue in order, processes it, and sends a response to the client.

Alternately, the consumer could put the result into a queue so that another thread (perhaps the listener thread?) can send the result to the client. In that case you'd have two producer/consumer relationships:

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

In .NET, this kind of thing is pretty easy to implement using BlockingCollection to handle the queues. I don't know if there is something similar in Java.

The possibility of a multi-message request complicates things a little bit, as it seems like the listener will have to buffer messages until the last part of the request comes in before placing the entire thing into the queue.

To me, the beauty of the producer/consumer design is that it forces a hard separation between different parts of the program, making each much easier to debug and minimizing the possibility of shared state causing problems. The only slightly complicated part here is that you'll have to include the connection (socket or whatever) as part of the message that gets shared in the queues so that the output thread knows where to send the response.

It's not clear to me if you have to process all messages in the order they're received or if you just need to process messages for any particular client in the proper order. For example, if you have:

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

Is it okay to process the first message from Client 2 before you process the second message from Client 1? If so, then you can increase throughput by using what is logically multiple queues--one per client. Your "consumer" then becomes multiple threads. You just have to make sure that only one message per client is being processed at any time.

I would have one thread per client which does the parsing and processing. That way the processing would be in the order it is sent/arrives.

As you have stated, the tasks cannot be perform in parallel safely. performing the parsing and processing in different threads is likely to add as much overhead as you might save.

If your processing is relatively simple and doesn't depend on external systems, a single thread should be able to handle 1K to 20K messages per second.

Is there any other issues you would want to fix?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM