<p>I'm implementing a custom protocol over TCP. Unlike HTTP, where the client issues a request and the server responds, this protocol also allows the server to issue requests which the client will respond to. A sample packet looks like this:</p>
<p><code>STX</code><code>TYPE</code><code>/</code><code>DATA</code><code>ETX</code></p>
<p>where <code>STX</code> is just 2 and <code>ETX</code> is just 3</p>
<p>Heres the possible request scenarios.</p>
<p>Scenario 1</p>
<p><code>Client -------REQUEST------> Server</code></p>
<p><code>Client <-----RESPONSE------- Server</code></p>
<p>Scenario 2</p>
<p><code>Client <------REQUEST-------- Server</code></p>
<p><code>Client -------RESPONSE------> Server</code></p>
<p>My first intuition is to fire a goroutine that will read <code>net.Conn</code> and parse the packet to determine what type of operation it is. Then I will send it to a <code>chan</code> of that type, <a href="https://gist.github.com/anonymous/8246c2ec615fc101f567ce536f5d284a#file-client-go-L88">here</a> it is. Scenario 1 is synchronous, as implemented in the <code>Send</code> function <a href="https://gist.github.com/anonymous/8246c2ec615fc101f567ce536f5d284a#file-client-go-L62">here</a>. <a href="https://gist.github.com/anonymous/8246c2ec615fc101f567ce536f5d284a#file-client-go-L109">Here</a> is how scenario 2 is handled. This works ok on small workloads but during load testing, say calling <code>Send</code> 400 times per second, the function times out. I even check the packet trace using wireshark and i can confirm that the server indeed sent a response, however it seems like the <code>readLoop</code> failed to pick it up and send it to the appropriate channel in which <code>Send</code> is trying to receive. Take note that this is a simplified version of the client/protocol, however all the semantics are the same. Any advice would be of great help. Thanks!</p>
<hr/>**评论:**<br/><br/>epiris: <pre><p>Sounds like requests are queueing but not being read somewhere. I would write tests for your parser funcs to assert they are correct with local buffers. Static valid known data, then try having them write
And drain the same buffers and see if you can find any issues. I wouldn't introduce tcp until you can see exactly where your issues are in tests. Main point here is to be sure your protocol has correct semantics that are comparable with your transport. That is the current flow of information is always clear, client requests the mode to change from sending msgs to receiving them. Obviously you can't just write from the server to the client while your client is expecting some kind of ack from their previous message, it's essentially a deadlock and sounds similar to what you describe here.</p></pre>newbgopher: <pre><p>sounds reasonable. fwiw i have unit test for all the parsing functions. requests from the server is async and client doesnt have to change the mode. its expected behaviour is to handle incoming requests in a concurrent manner.</p></pre>epiris: <pre><p>The network model your attempting is very error prone if you never have explicit synchronization for your requests and responses. It's sometimes reasonable to setup a second connection for a protocol that needs to send bulk data, like ftp. But I would probably re-evaluate hand rolling your own protocol and look at grpc or other protocols with clear semantics covering all the edge cases if this isn't just for learning. If for learning, debug away friend, you are likely having your internal state become out of sync under high throughput, waiting for an ACK on both sides somewhere.</p></pre>newbgopher: <pre><p>thanks. fwiw the protocol im trying to implement is an industry standard in telco. im aware of mainstream protocols but unfortunately the server that i'm trying to connect to only speaks this protocol. </p></pre>epiris: <pre><blockquote>
<p>I'm implementing a custom protocol over TCP.</p>
</blockquote>
<p>A industry standard in telco.. might of been good to include the standard instead of saying it was "custom". Heh.</p></pre>newbgopher: <pre><p>its a protocol by nokia, cimd. the protocol parsing is straight forward since its just key value pairs. the tricky part is the request coming from the server that needs to be acked.</p></pre>adzeitor: <pre><p>Try remove default in select from <code>respondToServer</code></p></pre>Thaxll: <pre><p>Didn't look at the code but did you try to profile it to see where is the bottleneck? <a href="https://golang.org/pkg/net/http/pprof/" rel="nofollow">https://golang.org/pkg/net/http/pprof/</a></p></pre>robbawebba: <pre><p>Is the <code>Send()</code> function ever being called? I couldn't see where it's being called, if it is. Messages being added to <code>client.bCh</code> are blocking until they are picked up in the send() function, which might not be happening.</p></pre>newbgopher: <pre><p>obviously this code is written as a library. </p></pre>robbawebba: <pre><p>Regardless of this being a library, won’t the channel still block that goroutine until send() is called by the user? I’m relatively new to concurrency in go, so this might be a naive thought, but it’s one of the first rules I learned when working with channels. </p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传