How to do streaming over binary TCP/IP based protocol in Go?

xuanbao · · 445 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I have a sample code in C#. It uses Core.Streaming to do the stuff. I have tried using DialTCP() from &#39;net&#39; but no luck. </p> <p>Here&#39;s C# sample code: </p> <pre><code>var client = new StreamingClient(); client.CompressionType = PacketCompressionType.Gzip; client.EncodingType = PacketEncodingType.Json; client.PacketReceived += new StreamingClient.PacketReceivedHandler(client_PacketReceived); try { var auth = client.Connect(&#34;export.kt01.net&#34;, 11011, &#34;username&#34;, &#34;password&#34;); Console.WriteLine(&#34;Connected (&#34; + auth.queueLength + &#34; items in queue)...&#34;); while (client.Connected) { Thread.Sleep(100); if (Console.KeyAvailable) { terminated = true; Console.Write(&#34;Stopping...&#34;); break; } } } catch (Exception ex) { Console.WriteLine(&#34;[ERROR] &#34; + ex.Message); Thread.Sleep(1000); // wait a second before retrying } finally { client.Disconnect(); Console.WriteLine(&#34;Disconnected&#34;); } </code></pre> <hr/>**评论:**<br/><br/>neondirt: <pre><p>Maybe try posting your Go code instead? Also, explain why it doesn&#39;t work (as you expected) and any errors you receive.</p></pre>jhadi: <pre><pre><code>func main() { user := &amp;User{Username: &#34;dummy&#34;,Password: &#34;dummy&#34;} jsondata, err := json.Marshal(user) if err != nil { fmt.Println(err) return } fmt.Println(string(jsondata)) if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, &#34;Usage: %s host:port &#34;, os.Args[0]) os.Exit(1) } service := os.Args[1] tcpAddr, err := net.ResolveTCPAddr(&#34;tcp&#34;, service) checkError(err) conn, err := net.DialTCP(&#34;tcp&#34;, nil, tcpAddr) checkError(err) _, err = conn.Write([]byte(jsondata)) checkError(err) result, err := ioutil.ReadAll(conn) checkError(err) fmt.Println(string(result)) os.Exit(0) </code></pre> <p>}</p> <p>I have to send username and password in json format, after that server will send me auth response. Currently I just receive &#34;connection reset by peer&#34; error. </p></pre>jerf: <pre><blockquote> <p>I have to send username and password in json format, after that server will send me auth response. Currently I just receive &#34;connection reset by peer&#34; error. </p> </blockquote> <p>Mmmm, that&#39;s tricky to get right. Are you responsible for the server on the other end or speaking to somebody else&#39;s server?</p> <p>JSON doesn&#39;t have an end-of-JSON delimiter. A streaming parser can notice when the stream has ended, but it is very easy to imagine that the server is not using a streaming parser and is instead looking for some delimiter to indicate that the JSON is done, like a newline or something. The difference could be something as simple as your C# happens to incidentally terminate the JSON with a CRLF, which the server was looking for as the sign to send the block of text to the parser, and the Go code isn&#39;t emitting it.</p> <p>If you do control both sides of the connection, I recommend delimiting the connection with something, for better reliability and debugging. Something as simple as &#34;4 bytes in network order indicating the length of the JSON to come&#34; is enough to solve that problem.</p> <p>If that is not the problem, you may want to wrap the conn with something that prints all the bytes going in and out, so you can see exactly what&#39;s going on.</p></pre>jhadi: <pre><p>Unfortunately, I&#39;m not responsible for the server on the other end. I&#39;ll try printing all the bytes though. Thanks</p></pre>: <pre><p>[deleted]</p></pre>jerf: <pre><p><a href="/u/jhadi" rel="nofollow">/u/jhadi</a>: This is a good suggestion, and what I&#39;m about to say is not disagreement with paul2048, but elaboration.</p> <p>Telnet doesn&#39;t work like a lot of people expect. By default it buffers entire lines before sending them over, which means you can telnet to a port, and type in the whole line of JSON, and backspace and such, and the server won&#39;t get the backspaces (which it won&#39;t know what to do with), it just gets the line.</p> <p>But when it gets that line, it will also have the \n in it from when you pushed enter, so bear that in mind; it may still be a difference between what you do and what your code does, even if you copy and paste the exact same JSON line into the telnet client.</p> <p>(Many people don&#39;t realize this is Telnet&#39;s default behavior because when you telnet to a shell, the shell immediately puts the Telnet connection in &#34;raw&#34; mode, which sends all keystrokes instantly. The Telnet protocol, which exists and is a thing, has a command for that. This is also why telnet is such a good default client for line-based connections like HTTP; you still can edit a line before sending it along, since there aren&#39;t very many, if any, protocols that will accept embedded backspace characters and process them. Which is a good thing; they all would have broken in the Unicode era.)</p></pre>neondirt: <pre><p>I guess that seems fine. Since you&#39;re getting &#34;reset by peer&#34;, have you verified that you&#39;re sending the correct message? Tried writing the json data to stdout?</p></pre>jhadi: <pre><p>I have made a struct for user:</p> <pre><code>type User struct { Username string `json:&#34;username&#34;` Password string `json:&#34;password&#34;` } </code></pre> <p>and then I initialize it using username and password: </p> <pre><code>user := &amp;User{Username: &#34;dummy&#34;,Password: &#34;dummy&#34;} </code></pre> <p>after that I convert it to json: </p> <pre><code>jsondata, err := json.Marshal(user) if err != nil { fmt.Println(err) return } fmt.Println(string(jsondata)) </code></pre> <p>once Println executes I get:</p> <pre><code>{&#34;username&#34;: &#34;dummy&#34;, &#34;password&#34;: &#34;dummy&#34;} </code></pre> <p>However the I&#39;m required it to send in this format: </p> <pre><code>{ &#34;username&#34;: &#34;dummy&#34;, &#34;password&#34;: &#34;password&#34; } </code></pre> <p>I thought skipping newlines might not be the issue. But I&#39;ll try this way too. </p></pre>neondirt: <pre><p>But have you compared it to what the C# code sends? White-space sensitivity isn&#39;t unheard of, unfortunately...</p></pre>Morgahl: <pre><p>Make sure you are handling that gzip data on the go end. Given the code you&#39;ve shown this is not the case.</p></pre>nsd433: <pre><p>You can try comparing packet captures of the working C# and the non-working Go clients in wireshark or similar tools that can follow a TCP connection (that makes it easier than reassembling the stream from raw packets, though it does hide where the Push flags happened)</p></pre>Defender90: <pre><p>This may not help you but I had to implement a client for a wacky 1980&#39;s binary protocol that was built for serial lines and ported by the manufacturer to TCP/IP. Maybe you can use this as a guide:</p> <p><a href="https://github.com/chrissnell/gopherwx/blob/master/station.go" rel="nofollow">https://github.com/chrissnell/gopherwx/blob/master/station.go</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

445 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传