{"id":140,"date":"2021-05-10T11:03:13","date_gmt":"2021-05-10T03:03:13","guid":{"rendered":"https:\/\/blog.king011.com\/?p=140"},"modified":"2021-05-10T11:04:02","modified_gmt":"2021-05-10T03:04:02","slug":"net-listener-%e6%8a%80%e5%b7%a7-net-pipe-%e7%9a%84%e5%a6%99%e7%94%a8","status":"publish","type":"post","link":"https:\/\/blog.king011.com\/?p=140","title":{"rendered":"net.Listener \u6280\u5de7 net.Pipe \u7684\u5999\u7528"},"content":{"rendered":"\n<p>golang \u7684 net.Listener \u548c ne.Conn \u5be6\u5728\u662f\u5f88\u597d\u7528\uff0c\u6a19\u6e96\u5eab\u7684 Listener Conn \u63a5\u53e3\u7232\u7db2\u8def\u901a\u8a0a\u5b9a\u7fa9\u4e86\u6a19\u6e96\u7684\u51fd\u6578\u7c3d\u540d\uff0c\u6240\u4ee5\u4efb\u4f55\u7b26\u5408\u6b64\u7c3d\u540d\u7684 golang \u4ee3\u78bc\u90fd\u53ef\u4ee5\u4e92\u76f8\u5354\u4f5c\u3002\u5148\u770b\u4e0b <a rel=\"noreferrer noopener\" href=\"https:\/\/golang.org\/pkg\/net\/#Listener\" target=\"_blank\">Listener<\/a> \u5b9a\u7fa9\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ A Listener is a generic network listener for stream-oriented protocols.\n\/\/\n\/\/ Multiple goroutines may invoke methods on a Listener simultaneously.\ntype Listener interface {\n\t\/\/ Accept waits for and returns the next connection to the listener.\n\tAccept() (Conn, error)\n\n\t\/\/ Close closes the listener.\n\t\/\/ Any blocked Accept operations will be unblocked and return errors.\n\tClose() error\n\n\t\/\/ Addr returns the listener's network address.\n\tAddr() Addr\n}<\/code><\/pre>\n\n\n\n<p>\u518d\u770b\u4e0b <a href=\"https:\/\/golang.org\/pkg\/net\/#Conn\" target=\"_blank\" rel=\"noreferrer noopener\">Conn<\/a> \u5b9a\u7fa9\u5982\u4e0b(\u7701\u7565\u4e86\u90e8\u5206\u5167\u5bb9\u53ea\u4fdd\u7559\u4e86\u4e3b\u8981\u7c3d\u540d)\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Conn is a generic stream-oriented network connection.\n\/\/\n\/\/ Multiple goroutines may invoke methods on a Conn simultaneously.\ntype Conn interface {\n\t\/\/ Read reads data from the connection.\n\t\/\/ Read can be made to time out and return an error after a fixed\n\t\/\/ time limit; see SetDeadline and SetReadDeadline.\n\tRead(b &#91;]byte) (n int, err error)\n\n\t\/\/ Write writes data to the connection.\n\t\/\/ Write can be made to time out and return an error after a fixed\n\t\/\/ time limit; see SetDeadline and SetWriteDeadline.\n\tWrite(b &#91;]byte) (n int, err error)\n\n\t\/\/ Close closes the connection.\n\t\/\/ Any blocked Read or Write operations will be unblocked and return errors.\n\tClose() error\n\n\t...\n}<\/code><\/pre>\n\n\n\n<p>\u8acb\u4ed4\u7d30\u601d\u8003\u4e0b\u4e0a\u8ff0\u5169\u500b\u63a5\u53e3\uff0c\u5176\u5be6\u5b8c\u5168\u548c\u7db2\u8def\u901a\u8a0a\u7121\u95dc\uff0c\u61c9\u8a72\u7a31\u7232\u901a\u8a0a\u63a5\u53e3\uff0c\u4efb\u4f55\u6eff\u8db3\u6b64\u63a5\u53e3\u7684\u7d44\u4ef6\u90fd\u53ef\u4ee5\u901a\u4fe1\uff0c\u53ea\u4e0d\u904e\u6211\u5011\u901a\u5e38\u5c07\u5176\u7528\u65bc\u7db2\u8def\u901a\u4fe1\u4e26\u4e14\u6a19\u6e96\u5eab\u7232\u7db2\u8def\u901a\u4fe1\u5be6\u73fe\u4e86\u6b64\u5169\u500b\u63a5\u53e3\u3002<\/p>\n\n\n\n<p>\u6bd4\u5982\u6211\u5011\u53ef\u4ee5\u4f7f\u7528\u5167\u5b58\u4f86\u5be6\u73fe\u4e0a\u8ff0\u63a5\u53e3\u4f86\u66ff\u4ee3\u901a\u5e38\u7684 golang \u7db2\u8def\u5eab\uff0c\u65bc\u662f\u4f60\u6703\u767c\u73fe\u7db2\u8def\u5eab\u4e00\u4e0b\u5b50\u8b8a\u6210\u4e86\u7a0b\u5f0f\u5167\u5b58\u901a\u8a0a\u5eab\uff0c\u662f\u5426\u5f88\u6709\u8da3\u3002\u540c\u7406\u6309\u7167\u6b64\u601d\u8def\u5982\u679c\u4f60\u5beb\u4e00\u500b\u672c\u5730\u5167\u5b58\u901a\u8a0a\u7684\u7d44\u4ef6\uff0c\u8b93\u5176\u5be6\u73fe\u4e0a\u8ff0\u63a5\u53e3\uff0c\u4f60\u5728\u5fc5\u8981\u6642\u5c31\u53ef\u4ee5\u6beb\u4e0d\u8cbb\u529b\u7684\u5c07\u6b64\u7a0b\u5f0f\u6539\u6210\u7db2\u8def\u901a\u8a0a\u7d44\u4ef6\u3002<\/p>\n\n\n\n<p>\u56e0\u6b64\u672c\u55b5\u63a8\u85a6\uff0c\u7121\u8ad6\u662f\u5728\u5beb\u7db2\u8def\u901a\u8a0a\u7d44\u4ef6\u6216\u662f\u5167\u5b58\u4e2d\u591a\u500b goroutine \u9593\u901a\u8a0a\u6216\u5176\u5b83\u4ec0\u9ebc\u901a\u8a0a\u7d44\u4ef6\u4f60\u90fd\u61c9\u8a72\u5118\u91cf\u4f7f\u5176\u7b26\u5408 Listener Conn \u63a5\u53e3\u7684\u5b9a\u7fa9\uff0c\u5982\u6b64\u4ee3\u78bc\u5c07\u53ef\u5de5\u4f5c\u5728\u591a\u7a2e\u74b0\u5883(\u7db2\u8def\uff0c\u5167\u5b58&#8230;)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">net.Pipe<\/h2>\n\n\n\n<p>\u6a19\u6e96\u5eab <a rel=\"noreferrer noopener\" href=\"https:\/\/golang.org\/pkg\/net\/#Pipe\" target=\"_blank\">net.Pipe<\/a> \u51fd\u6578\u5728\u5167\u5b58\u4e2d\u5275\u5efa\u540c\u6b65\u7684\u5168\u96d9\u5de5\u901a\u8a0a\u7d44\u4ef6\uff0c\u4e26\u4e14\u5176\u5df2\u7d93\u5be6\u73fe\u4e86 net.Conn \u63a5\u53e3\u3002\u4e00\u7aef\u7684\u8b80\u53d6\u8207\u53e6\u4e00\u7aef\u7684\u5beb\u5165\u5339\u914d\uff0c\u6c92\u6709\u5167\u90e8\u7de9\u885d\u53ef\u4ee5\u9ad8\u6548\u7684\u5728\u5169\u8005\u9593\u8907\u88fd\u6578\u64da\u3002\u5176\u7c3d\u540d\u5982\u4e0b<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func Pipe() (Conn, Conn)<\/code><\/pre>\n\n\n\n<p>\u5df2\u7d93\u6709\u4e86\u5167\u5b58\u901a\u8a0a\u7684 net.Conn \u6211\u5011\u5728\u81ea\u5df1\u5be6\u73fe\u4e0b Listener \u5c31\u53ef\u4ee5\u8f15\u9b06\u7684\u5c07\u7db2\u8def\u7a0b\u5f0f\u548c\u5167\u5b58\u901a\u8a0a\u7a0b\u5f0f\u9593\u7121\u7e2b\u5207\u63db\uff0c\u6709\u4e86 Pipe \u5be6\u73fe Listener \u4e5f\u5f88\u7c21\u55ae\uff0c\u5275\u5efa\u4e00\u500b chan \u7576 Accept \u6642\u5f9e chan \u4e2d\u8b80\u53d6\u5373\u53ef\uff0c\u800cDial \u6642\u8abf\u7528 Pipe \u5c07 \u8fd4\u56de\u7684\u5169\u500b Conn \u4e00\u500b\u50b3\u5165 chan \u53e6\u4e00\u500b\u8fd4\u56de\u7d66\u8abf\u7528\u8005\u5373\u53ef\uff0c\u672c\u55b5\u7684\u5be6\u73fe\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n\t\"sync\/atomic\"\n)\n\nvar ErrPipeListenerClosed = errors.New(`pipe listener already closed`)\n\ntype PipeListener struct {\n\tch    chan net.Conn\n\tclose chan struct{}\n\tdone  uint32\n\tm     sync.Mutex\n}\n\nfunc ListenPipe() *PipeListener {\n\treturn &amp;PipeListener{\n\t\tch:    make(chan net.Conn),\n\t\tclose: make(chan struct{}),\n\t}\n}\n\n\/\/ Accept waits for and returns the next connection to the listener.\nfunc (l *PipeListener) Accept() (c net.Conn, e error) {\n\tselect {\n\tcase c = &lt;-l.ch:\n\tcase &lt;-l.close:\n\t\te = ErrPipeListenerClosed\n\t}\n\treturn\n}\n\n\/\/ Close closes the listener.\n\/\/ Any blocked Accept operations will be unblocked and return errors.\nfunc (l *PipeListener) Close() (e error) {\n\tif atomic.LoadUint32(&amp;l.done) == 0 {\n\t\tl.m.Lock()\n\t\tdefer l.m.Unlock()\n\t\tif l.done == 0 {\n\t\t\tdefer atomic.StoreUint32(&amp;l.done, 1)\n\t\t\tclose(l.close)\n\t\t\treturn\n\t\t}\n\t}\n\te = ErrPipeListenerClosed\n\treturn\n}\n\n\/\/ Addr returns the listener's network address.\nfunc (l *PipeListener) Addr() net.Addr {\n\treturn pipeAddr(0)\n}\nfunc (l *PipeListener) Dial(network, addr string) (net.Conn, error) {\n\treturn l.DialContext(context.Background(), network, addr)\n}\nfunc (l *PipeListener) DialContext(ctx context.Context, network, addr string) (conn net.Conn, e error) {\n\t\/\/ check closed\n\tif atomic.LoadUint32(&amp;l.done) != 0 {\n\t\te = ErrPipeListenerClosed\n\t\treturn\n\t}\n\n\t\/\/ pipe\n\tc0, c1 := net.Pipe()\n\t\/\/ waiting accepted or closed or done\n\tselect {\n\tcase &lt;-ctx.Done():\n\t\te = ctx.Err()\n\tcase l.ch &lt;- c0:\n\t\tconn = c1\n\tcase &lt;-l.close:\n\t\tc0.Close()\n\t\tc1.Close()\n\t\te = ErrPipeListenerClosed\n\t}\n\treturn\n}\n\ntype pipeAddr int\n\nfunc (pipeAddr) Network() string {\n\treturn `pipe`\n}\nfunc (pipeAddr) String() string {\n\treturn `pipe`\n}<\/code><\/pre>\n\n\n\n<p>\u6700\u5f8c\u4f86\u5beb\u500b\u8abf\u7528\u4ee3\u78bc\u4f86\u5c07 http \u4e2d\u4f7f\u7528\u7684 tcp \u901a\u8a0a\u6539\u7232\u5167\u5b58\u901a\u8a0a\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\/ioutil\"\n\t\"log\"\n\t\"net\"\n\t\"net\/http\"\n)\n\nfunc main() {\n\tlog.SetFlags(log.Lshortfile | log.LstdFlags)\n\tl := ListenPipe()\n\tlog.Println(`listen on pipe`)\n\tgo runServer(l)\n\trunClient(l.Dial, l.DialContext)\n}\nfunc runClient(dial func(network, addr string) (net.Conn, error), dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) {\n\tclient := &amp;http.Client{\n\t\tTransport: &amp;http.Transport{\n\t\t\tDial:        dial,\n\t\t\tDialContext: dialContext,\n\t\t},\n\t}\n\tprintResponse(client.Get(`http:\/\/localhost\/speak`))\n\tprintResponse(client.Get(`http:\/\/localhost\/version`))\n}\nfunc printResponse(resp *http.Response, e error) {\n\tif e != nil {\n\t\tlog.Fatalln(e)\n\t}\n\tb, e := ioutil.ReadAll(resp.Body)\n\tif e != nil {\n\t\tlog.Fatalln(e)\n\t}\n\tfmt.Println(resp.Status)\n\tfmt.Println(string(b))\n}\nfunc runServer(l net.Listener) {\n\tm := http.NewServeMux()\n\tm.HandleFunc(`\/speak`, func(rw http.ResponseWriter, r *http.Request) {\n\t\trw.Header().Set(`Content-Type`, `text\/plain; charset=utf-8`)\n\t\trw.Write(&#91;]byte(`server serve on pipe`))\n\t})\n\tm.HandleFunc(`\/version`, func(rw http.ResponseWriter, r *http.Request) {\n\t\trw.Header().Set(`Content-Type`, `text\/plain; charset=utf-8`)\n\t\trw.Write(&#91;]byte(`pipe server v1.0.0`))\n\t})\n\thttp.Serve(l, m)\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u5176\u5b83\u6709\u8da3\u7684\u7528\u6cd5<\/h2>\n\n\n\n<p>\u9664\u53bb\u4e0a\u8ff0\u7528\u6cd5\uff0c\u672c\u55b5\u4e5f\u60f3\u5230\u4e86\u53e6\u5916\u4e00\u4e9b\u6709\u8da3\u7684\u73a9\u6cd5\uff0c\u6b64\u8655\u53ea\u662f\u4e00\u63d0\uff0c\u5982\u679c\u5f8c\u9762\u6709\u7a7a\u5c07\u55ae\u7368\u767c\u4f48\u6587\u7ae0\u8a0e\u8ad6\u5be6\u73fe\u7d30\u7bc0\u3002<\/p>\n\n\n\n<p>grpc-gateway \u662f\u4e00\u500b grpc \u7684\u53cd\u5411\u4ee3\u7406\uff0c\u53ef\u4ee5\u7232 grpc \u63d0\u4f9b\u4e00\u500b http \u76841.1\u517c\u5bb9\u63a5\u53e3\uff0c\u5176\u539f\u7406\u662f\u63d0\u4f9b\u4e86\u4e00\u5957 http \u63a5\u53e3\u4f9b\u8abf\u7528\u8005\u4f7f\u7528 http \u8abf\u7528\uff0c\u5167\u90e8\u767c\u9001 grpc \u8acb\u6c42\u5230 grpc \u670d\u52d9\uff0c\u6700\u5f8c\u5c07 grpc \u7684\u97ff\u61c9\u518d\u8f49\u7232 http \u97ff\u61c9\u8fd4\u56de\u7d66\u8abf\u7528\u8005\u3002gateway \u5230 grpc \u9593\u7684\u901a\u8a0a\u8981\u7d93\u904e\u7db2\u5361\u4f7f\u7528 tcp \u5354\u8b70\u901a\u8a0a\uff0c\u5982\u679c gateway \u548c grpc \u5728\u540c\u500b\u670d\u52d9\u5668\u4e0a\u5176\u5be6\u53ef\u4ee5\u5c07\u5b83\u5011\u653e\u5230\u4e00\u500b\u7a0b\u5f0f\u4e2d\u4e26\u8b93 grpc \u5de5\u4f5c\u5728\u4e0a\u8ff0\u7684 PipeListener \u63a5\u53e3\u4e0a\uff0c\u9019\u6a23\u5c31\u53ef\u4ee5\u8b93 gateway \u548c grpc \u76f4\u63a5\u5167\u5b58\u901a\u8a0a\u800c\u4e0d\u7528\u7d93\u904e\u7db2\u5361\u3002<\/p>\n\n\n\n<p>\u53cd\u5411\u6728\u99ac\u5beb\u8d77\u4f86\u5f88\u7c21\u55ae\u4f46\u5f88\u7e41\u7463\uff0c\u5982\u679c\u53ef\u4ee5\u7528 grpc \u5247\u6703\u7c21\u55ae\u5f88\u591a\uff0c\u53ef\u4ee5\u81ea\u5df1\u5be6\u73fe Listener \u8b93\u64a5\u865f\u7684\u6728\u99ac\u7aef\u4f5c\u7232 grpc \u670d\u52d9\u5668\u9019\u770b\u8d77\u4f86\u4e5f\u5f88\u6709\u8da3\u3002\u53e6\u5916\u4e0d\u6b62\u53cd\u5411\u6728\u99ac\u5176\u5be6\u53ea\u8981\u662f\u985e\u4f3c\u9019\u7a2e\u9700\u8981\u985b\u5012\u64a5\u865f\u65b9\u7684\u60c5\u6cc1\u90fd\u53ef\u4ee5\u4f7f\u7528\u81ea\u5df1\u5be6\u73fe\u7684 Listener \u4f86\u8b93\u5176\u4ee3\u78bc\u770b\u8d77\u4f86\u548c\u6c92\u6709\u985b\u5012\u7684\u6b63\u5e38\u7a0b\u5f0f\u4e00\u6a23\u8212\u670d\u3002<\/p>\n\n\n\n<p>\u6b64\u5916\u5c07\u4e00\u500b\u5354\u8b70\u7684 Listener \u5957\u5230\u53e6\u5916\u4e00\u500b\u5354\u8b70\u7684 Listener \u4e00\u4e0b\u5b50\u5c31\u5be6\u73fe\u4e86\u5404\u7a2e over \u64cd\u4f5c\uff0c\u6bd4\u5982 vnc over ssh\uff0cssh over websocket\uff0c\u751a\u81f3 vnc over ssh over websocket \u4e4b\u985e\u7684\u6709\u8da3\u4e8b\u60c5\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>golang \u7684 net.Listener \u548c ne.Conn \u5be6\u5728\u662f\u5f88\u597d\u7528\uff0c\u6a19\u6e96\u5eab\u7684 Listener Co [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[11,2],"tags":[12,29,27,24,28,26,25],"class_list":["post-140","post","type-post","status-publish","format-standard","hentry","category-golang","category-code","tag-golang","tag-listener","tag-memorylistener","tag-net","tag-net-listener","tag-net-pipe","tag-pipe"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":6}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.king011.com\/index.php?rest_route=\/wp\/v2\/posts\/140","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.king011.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.king011.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.king011.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.king011.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=140"}],"version-history":[{"count":23,"href":"https:\/\/blog.king011.com\/index.php?rest_route=\/wp\/v2\/posts\/140\/revisions"}],"predecessor-version":[{"id":163,"href":"https:\/\/blog.king011.com\/index.php?rest_route=\/wp\/v2\/posts\/140\/revisions\/163"}],"wp:attachment":[{"href":"https:\/\/blog.king011.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=140"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.king011.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=140"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.king011.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=140"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}