Implementing a custom TCP client

123 views
Skip to first unread message

newbg...@gmail.com

unread,
Sep 20, 2017, 8:26:41 AM9/20/17
to golang-nuts
Hi all!
I already asked this on reddit, but I figured might as well ask it here.
Im trying to implement a custom TCP client. This protocol allows request from both the client and the server


Scenario 1:

Client -------REQUEST------> Server

Client <-----RESPONSE------- Server


Scenario 2:

Client <------REQUEST-------- Server

Client -------RESPONSE------> Server



Here's simplified form of the client. This approach uses a goroutine to read the net.Conn, parse the string to determine the type, 
and send the string to the appropriate channel for that type. Typical usage of this client is as follows

    c := client.New("localhost:8888")
    c.Connect()
    c.Send("message")

On small workloads, it works fine, however calling Send around 100 times a second times out. 
I can confirm using wireshark that the server indeed sent a response, however it seems like the readLoop wasn't able read it and send it to the channel.
I would like to ask if this approach is reasonable. Id like to ask anyone out there have implemented a client golang library thats able to both send and receive requests from  the server. Basically a bidirectional tcp client. I know nats is similar to this, however their protocol parsing is too complex for me. Any new approach/advise will be nice. Thanks!




Tamás Gulácsi

unread,
Sep 20, 2017, 9:03:14 AM9/20/17
to golang-nuts
I don't see anything obviously wrong, but using length-prefixed messages would simplify reading (no need to buffer) and wouldn't complicate writing.
My 2¢

Slawomir Pryczek

unread,
Sep 21, 2017, 8:04:15 PM9/21/17
to golang-nuts
Hi, your problem is that you need message length to be embedded somewhere, preferable at the message beginning because otherwise >1 message could be merged into single packet and you won't know where it is supposed to end. Eg. if you send small messages 100 times, more messages will be merged into larger TCP packet, so you'll only receive data eg. 10 times, but you still need to know there is 100 requests there, to send 100 responses. Also single message can be split into several packets / will require >1 read call to get fully.

If you have no length (nor unique suffix) you can't know if message ended and you need to start processing it, or there are link issues and you should return a timeout error and maybe re-try. I have project like this on github. It's golang TCP server and php TCP client https://github.com/slawomir-pryczek/HSServer

Writing client is much easier, and TCP for server is implemented in single file basically ( https://github.com/slawomir-pryczek/HSServer/blob/master/go/src/handler_socket2/handler_socket.go ) ...  so you can take a look ;) Only things which are not so obvious at first is that you need to know exactly how long the message is, when to finish reading and start sending, and you need some code to detect errors so you can close connection (and later re-open it, instead of sending more data when your link is in failed state, if there are some issues).


If you have 2 way blocking communication (C -> S, S->C) and you'll begin sending your response back BEFORE receiving full (single) request from the client, then you'll break the process because client could get blocked on Send while Server will also block because it's already sending BUT client is not ready to receive... so you'll have a deadlock as both C and S will try to send data at the same time.
Reply all
Reply to author
Forward
0 new messages