{"id":4169,"date":"2018-11-10T11:58:47","date_gmt":"2018-11-10T03:58:47","guid":{"rendered":"https:\/\/ixyzero.com\/blog\/?p=4169"},"modified":"2018-11-10T11:58:47","modified_gmt":"2018-11-10T03:58:47","slug":"go%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a017-%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8ctcp-socket%e7%bc%96%e7%a8%8b","status":"publish","type":"post","link":"https:\/\/ixyzero.com\/blog\/archives\/4169.html","title":{"rendered":"Go\u8bed\u8a00\u5b66\u4e60#17-\u5982\u4f55\u8fdb\u884cTCP socket\u7f16\u7a0b"},"content":{"rendered":"<p>=Start=<\/p>\n<h4 id=\"id-\u6a21\u677f-\u7f18\u7531\uff1a\">\u7f18\u7531\uff1a<\/h4>\n<p>\u5b66\u4e60\u3001\u6574\u7406\u4e00\u4e0b\u5982\u4f55\u7528Go\u8bed\u8a00\u8fdb\u884cTCP socket\u7f16\u7a0b\uff0c\u65b9\u4fbf\u4ee5\u540e\u9700\u8981\u7684\u65f6\u5019\u8fdb\u884c\u53c2\u8003\u548c\u4f7f\u7528\u3002<\/p>\n<h4 id=\"id-\u6a21\u677f-\u6b63\u6587\uff1a\">\u6b63\u6587\uff1a<\/h4>\n<h5 id=\"id-\u6a21\u677f-\u53c2\u8003\u89e3\u7b54\uff1a\">\u53c2\u8003\u89e3\u7b54\uff1a<\/h5>\n<p><span style=\"color: #ff0000;\">\u57fa\u4e8eTCP\uff08\u9762\u5411\u8fde\u63a5\uff09\u7684socket\u7f16\u7a0b\uff0c\u5206\u4e3a\u5ba2\u6237\u7aef\u548c\u670d\u52a1\u5668\u7aef\u3002<\/span><\/p>\n<p>\u5ba2\u6237\u7aef\u7684\u6d41\u7a0b\u5982\u4e0b\uff1a<br \/>\n\uff081\uff09\u521b\u5efa\u5957\u63a5\u5b57\uff08socket\uff09<br \/>\n\uff082\uff09\u5411\u670d\u52a1\u5668\u53d1\u51fa\u8fde\u63a5\u8bf7\u6c42\uff08connect\uff09<br \/>\n\uff083\uff09\u548c\u670d\u52a1\u5668\u7aef\u8fdb\u884c\u901a\u4fe1\uff08send\/recv\uff09<br \/>\n\uff084\uff09\u5173\u95ed\u5957\u63a5\u5b57\uff08close\uff09<\/p>\n<p>\u670d\u52a1\u5668\u7aef\u7684\u6d41\u7a0b\u5982\u4e0b\uff1a<br \/>\n\uff081\uff09\u521b\u5efa\u5957\u63a5\u5b57\uff08socket\uff09<br \/>\n\uff082\uff09\u5c06\u5957\u63a5\u5b57\u7ed1\u5b9a\u5230\u4e00\u4e2a\u672c\u5730\u5730\u5740\u548c\u7aef\u53e3\u4e0a\uff08bind\uff09<br \/>\n\uff083\uff09\u5c06\u5957\u63a5\u5b57\u8bbe\u4e3a\u76d1\u542c\u6a21\u5f0f\uff0c\u51c6\u5907\u63a5\u6536\u5ba2\u6237\u7aef\u8bf7\u6c42\uff08listen\uff09<br \/>\n\uff084\uff09\u7b49\u5f85\u5ba2\u6237\u8bf7\u6c42\u5230\u6765\uff1b\u5f53\u8bf7\u6c42\u5230\u6765\u540e\uff0c\u63a5\u53d7\u8fde\u63a5\u8bf7\u6c42\uff0c\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u5bf9\u5e94\u4e8e\u6b64\u6b21\u8fde\u63a5\u7684\u5957\u63a5\u5b57\uff08accept\uff09<br \/>\n\uff085\uff09\u7528\u8fd4\u56de\u7684\u5957\u63a5\u5b57\u548c\u5ba2\u6237\u7aef\u8fdb\u884c\u901a\u4fe1\uff08send\/recv\uff09<br \/>\n\uff086\uff09\u8fd4\u56de\uff0c\u7b49\u5f85\u53e6\u4e00\u4e2a\u5ba2\u6237\u8bf7\u6c42<br \/>\n\uff087\uff09\u5173\u95ed\u5957\u63a5\u5b57\uff08close\uff09<\/p>\n<hr \/>\n<p>\u4eceTCP socket\u8bde\u751f\u540e\uff0c\u7f51\u7edc\u7f16\u7a0b\u67b6\u6784\u6a21\u578b\u4e5f\u51e0\u7ecf\u6f14\u5316\uff0c\u5927\u81f4\u662f\uff1a\u201c\u6bcf\u8fdb\u7a0b\u4e00\u4e2a\u8fde\u63a5\u201d \u2013&gt; \u201c\u6bcf\u7ebf\u7a0b\u4e00\u4e2a\u8fde\u63a5\u201d \u2013&gt; \u201cNon-Block + I\/O\u591a\u8def\u590d\u7528(linux epoll\/windows iocp\/freebsd darwin kqueue\/solaris Event Port)\u201d\u3002\u4f34\u968f\u7740\u6a21\u578b\u7684\u6f14\u5316\uff0c\u670d\u52a1\u7a0b\u5e8f\u6108\u52a0\u5f3a\u5927\uff0c\u53ef\u4ee5\u652f\u6301\u66f4\u591a\u7684\u8fde\u63a5\uff0c\u83b7\u5f97\u66f4\u597d\u7684\u5904\u7406\u6027\u80fd\u3002<\/p>\n<p>\u76ee\u524d\u4e3b\u6d41Web Server\u4e00\u822c\u5747\u91c7\u7528\u7684\u90fd\u662f\u201dNon-Block + I\/O\u591a\u8def\u590d\u7528\u201d\uff08\u6709\u7684\u4e5f\u7ed3\u5408\u4e86\u591a\u7ebf\u7a0b\u3001\u591a\u8fdb\u7a0b\uff09\u3002\u4e0d\u8fc7I\/O\u591a\u8def\u590d\u7528\u4e5f\u7ed9\u4f7f\u7528\u8005\u5e26\u6765\u4e86\u4e0d\u5c0f\u7684\u590d\u6742\u5ea6\uff0c\u4ee5\u81f3\u4e8e\u540e\u7eed\u51fa\u73b0\u4e86\u8bb8\u591a\u9ad8\u6027\u80fd\u7684I\/O\u591a\u8def\u590d\u7528\u6846\u67b6\uff0c \u6bd4\u5982<a class=\"underlink bluelink\" tabindex=\"-1\" href=\"http:\/\/libevent.org\/\" target=\"_blank\" rel=\"noopener\">libevent<\/a>\u3001<a class=\"underlink bluelink\" tabindex=\"-1\" href=\"http:\/\/software.schmorp.de\/pkg\/libev.html\" target=\"_blank\" rel=\"noopener\">libev<\/a>\u3001<a class=\"underlink bluelink\" tabindex=\"-1\" href=\"https:\/\/github.com\/joyent\/libuv\" target=\"_blank\" rel=\"noopener\">libuv<\/a>\u7b49\uff0c\u4ee5\u5e2e\u52a9\u5f00\u53d1\u8005\u7b80\u5316\u5f00\u53d1\u590d\u6742\u6027\uff0c\u964d\u4f4e\u5fc3\u667a\u8d1f\u62c5\u3002\u4e0d\u8fc7Go\u7684\u8bbe\u8ba1\u8005\u4f3c\u4e4e\u8ba4\u4e3aI\/O\u591a\u8def\u590d\u7528\u7684\u8fd9\u79cd\u901a\u8fc7\u56de\u8c03\u673a\u5236\u5272\u88c2\u63a7\u5236\u6d41 \u7684\u65b9\u5f0f\u4f9d\u65e7\u590d\u6742\uff0c\u4e14\u6709\u6096\u4e8e\u201c\u4e00\u822c\u903b\u8f91\u201d\u8bbe\u8ba1\uff0c\u4e3a\u6b64Go\u8bed\u8a00\u5c06\u8be5\u201c\u590d\u6742\u6027\u201d\u9690\u85cf\u5728Runtime\u4e2d\u4e86\uff1a<span style=\"color: #ff0000;\">Go\u5f00\u53d1\u8005\u65e0\u9700\u5173\u6ce8socket\u662f\u5426\u662f non-block\u7684\uff0c\u4e5f\u65e0\u9700\u4eb2\u81ea\u6ce8\u518c\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u56de\u8c03\uff0c\u53ea\u9700\u5728\u6bcf\u4e2a\u8fde\u63a5\u5bf9\u5e94\u7684goroutine\u4e2d\u4ee5<strong>\u201cblock I\/O\u201d<\/strong>\u7684\u65b9\u5f0f\u5bf9\u5f85socket\u5904\u7406\u5373\u53ef\uff0c\u8fd9\u53ef\u4ee5\u8bf4\u5927\u5927\u964d\u4f4e\u4e86\u5f00\u53d1\u4eba\u5458\u7684\u5fc3\u667a\u8d1f\u62c5\u3002<\/span>\u4e00\u4e2a\u5178\u578b\u7684Go Server\u7aef\u7a0b\u5e8f\u5927\u81f4\u5982\u4e0b\uff1a<\/p>\n<pre class=\"lang:default decode:true \">func handleConn(c net.Conn) { \r\n    defer c.Close() \r\n    for { \r\n        \/\/ read from the connection \r\n        \/\/ ... ... \r\n        \/\/ write to the connection \r\n        \/\/... ... \r\n    } \r\n} \r\n\r\nfunc main() { \r\n    l, err := net.Listen(\"tcp\", \":8888\") \r\n    if err != nil { \r\n        fmt.Println(\"listen error:\", err) \r\n        return \r\n    }\r\n    defer l.Close()\r\n\r\n    for { \r\n        c, err := l.Accept() \r\n        if err != nil { \r\n            fmt.Println(\"accept error:\", err) \r\n            break \r\n        } \r\n        \/\/ start a new goroutine to handle \r\n        \/\/ the new connection. \r\n        go handleConn(c) \r\n    } \r\n}<\/pre>\n<hr \/>\n<p>\u4e0a\u9762\u7684\u5185\u5bb9\u53ef\u80fd\u66f4\u504f\u6982\u5ff5\u6027\u7684\u63cf\u8ff0\uff0c\u4e0b\u9762\u901a\u8fc7\u51e0\u4e2a\u7b80\u5355\u7684\u4f8b\u5b50\u5e2e\u52a9\u5efa\u7acb\u8d77\u76f4\u89c2\u7684\u8ba4\u8bc6\u3002<\/p>\n<p>\u5ba2\u6237\u7aef\u4ee3\u7801\uff1a<\/p>\n<pre class=\"lang:default decode:true \" title=\"go_tcp_echo_client.go\">package main\r\n\r\nimport (\r\n    \"bufio\"\r\n    \"fmt\"\r\n    \"net\"\r\n    \"os\"\r\n    \"strconv\"\r\n)\r\n\r\nconst (\r\n    SERVER_IP       = \"127.0.0.1\"\r\n    SERVER_PORT     = 10006\r\n    SERVER_RECV_LEN = 10\r\n)\r\n\r\nfunc checkError(err error) {\r\n    if err != nil {\r\n        fmt.Println(err)\r\n        os.Exit(1)\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    address := SERVER_IP + \":\" + strconv.Itoa(SERVER_PORT)\r\n    fmt.Printf(\"value of address: %v (%T)\\n\\n\", address, address)\r\n\r\n    conn, err := net.Dial(\"tcp\", address)\r\n    checkError(err)\r\n    defer conn.Close()\r\n\r\n    input := bufio.NewScanner(os.Stdin)\r\n    for input.Scan() {\r\n        line := input.Text()\r\n        lineLen := len(line)\r\n\r\n        n := 0\r\n        for written := 0; written &lt; lineLen; written += n {\r\n            var toWrite string\r\n            if lineLen-written &gt; SERVER_RECV_LEN {\r\n                toWrite = line[written : written+SERVER_RECV_LEN]\r\n            } else {\r\n                toWrite = line[written:]\r\n            }\r\n\r\n            n, err = conn.Write([]byte(toWrite))\r\n            checkError(err)\r\n\r\n            fmt.Println(\"Write:\", toWrite)\r\n\r\n            msg := make([]byte, SERVER_RECV_LEN)\r\n            n, err = conn.Read(msg)\r\n            checkError(err)\r\n\r\n            fmt.Println(\"Response:\", string(msg))\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>\u670d\u52a1\u7aef\uff08\u5355\u8fdb\u7a0b\/\u5355\u7ebf\u7a0b\/\u5355goroutine\uff09\u4ee3\u7801\uff1a<\/p>\n<pre class=\"lang:default decode:true \" title=\"go_tcp_echo_server.go\">package main\r\n\r\nimport (\r\n    \"fmt\"\r\n    \"net\"\r\n    \"os\"\r\n    \"strconv\"\r\n    \"strings\"\r\n)\r\n\r\nconst (\r\n    SERVER_IP       = \"127.0.0.1\"\r\n    SERVER_PORT     = 10006\r\n    SERVER_RECV_LEN = 10\r\n)\r\n\r\nfunc main() {\r\n    address := SERVER_IP + \":\" + strconv.Itoa(SERVER_PORT)\r\n    listener, err := net.Listen(\"tcp\", address)\r\n    if err != nil {\r\n        fmt.Println(err)\r\n        os.Exit(1)\r\n    }\r\n    defer listener.Close()\r\n\r\n    for {\r\n        conn, err := listener.Accept()\r\n        if err != nil {\r\n            fmt.Println(err)\r\n            continue\r\n        }\r\n        defer conn.Close()\r\n\r\n        fmt.Println(\"Client Info:\", conn.RemoteAddr().String())\r\n        for {\r\n            data := make([]byte, SERVER_RECV_LEN)\r\n            _, err = conn.Read(data)\r\n            if err != nil {\r\n                fmt.Println(err)\r\n                break\r\n            }\r\n\r\n            strData := string(data)\r\n            fmt.Println(\"Received:\", strData)\r\n\r\n            upper := strings.ToUpper(strData)\r\n            _, err = conn.Write([]byte(upper))\r\n            if err != nil {\r\n                fmt.Println(err)\r\n                break\r\n            }\r\n\r\n            fmt.Println(\"Send:\", upper)\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>\u4e0a\u9762\u7684\u670d\u52a1\u7aef\u7a0b\u5e8f\u5b58\u5728\u4e00\u4e2a\u95ee\u9898\uff0c\u90a3\u5c31\u662f\u4e00\u6b21\u53ea\u80fd\u4e3a\u4e00\u4e2a\u5ba2\u6237\u7aef\u63d0\u4f9b\u670d\u52a1(for\u5faa\u73af)\uff0c\u5982\u679c\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u65f6\u95f4\u8fc7\u957f\uff0c\u53ef\u80fd\u4f1a\u8ba9\u670d\u52a1\u5668\u65e0\u6cd5\u670d\u52a1\u4e8e\u5176\u4ed6\u7684\u5ba2\u6237\u7aef\uff0c\u8fd9\u5c31\u662f\u62d2\u7edd\u670d\u52a1\u653b\u51fb\uff0c\u6700\u7b80\u5355\u7684\u89e3\u51b3\u8fd9\u79cd\u95ee\u9898\u7684\u65b9\u5f0f\u5c31\u662f\u5c06conn\u7684\u5904\u7406\u5355\u72ec\u542f\u52a8\u7ebf\u7a0b\uff0c\u5728Go \u8bed\u8a00\u4e2d\u6211\u4eec\u53ea\u9700\u8981\u501f\u52a9\u4e8e go \u65b9\u6cd5\u542f\u52a8\u4e00\u4e2aroutine\u5373\u53ef\u3002<\/p>\n<pre class=\"lang:default decode:true \" title=\"go_tcp_echo_server2.go\">package main\r\n\r\nimport (\r\n    \"fmt\"\r\n    \"net\"\r\n    \"os\"\r\n    \"strconv\"\r\n    \"strings\"\r\n)\r\n\r\nconst (\r\n    SERVER_IP       = \"127.0.0.1\"\r\n    SERVER_PORT     = 10006\r\n    SERVER_RECV_LEN = 10\r\n)\r\n\r\nfunc main() {\r\n    address := SERVER_IP + \":\" + strconv.Itoa(SERVER_PORT)\r\n    listener, err := net.Listen(\"tcp\", address)\r\n    if err != nil {\r\n        fmt.Println(err)\r\n        os.Exit(1)\r\n    }\r\n    defer listener.Close()\r\n\r\n    for {\r\n        conn, err := listener.Accept()\r\n        if err != nil {\r\n            fmt.Println(err)\r\n            continue\r\n        }\r\n\r\n        go handleConn(conn)\r\n    }\r\n}\r\n\r\nfunc handleConn(conn net.Conn) {\r\n    defer conn.Close()\r\n\r\n    fmt.Println(\"Client Info:\", conn.RemoteAddr().String())\r\n    for {\r\n        data := make([]byte, SERVER_RECV_LEN)\r\n        _, err := conn.Read(data)\r\n        if err != nil {\r\n            fmt.Println(err)\r\n            break\r\n        }\r\n\r\n        strData := string(data)\r\n        fmt.Println(\"Received:\", strData)\r\n\r\n        upper := strings.ToUpper(strData)\r\n        _, err = conn.Write([]byte(upper))\r\n        if err != nil {\r\n            fmt.Println(err)\r\n            break\r\n        }\r\n\r\n        fmt.Println(\"Send:\", upper)\r\n    }\r\n}\r\n<\/pre>\n<p>\u5c06\u5ba2\u6237\u7aef\u6570\u636e\u5904\u7406\u7684\u90e8\u5206\u5c01\u88c5\u6210\u4e86\u4e00\u4e2ahandleConn\u51fd\u6570\uff0c\u5728\u4e0e\u5ba2\u6237\u7aef\u8fde\u63a5\u5efa\u7acb\u65f6\uff0c\u901a\u8fc7Go \u8bed\u8a00\u7684go\u5173\u952e\u5b57\u8c03\u7528handleConn\u51fd\u6570\uff0c\u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u534f\u7a0b\u8fdb\u884c\u5904\u7406\uff0c\u8fd9\u6837\uff0cmain\u51fd\u6570\u4f1a\u7acb\u523b\u91cd\u65b0\u963b\u585e\u5728Accept\u4e0a\uff0c\u4ece\u800c\u4fdd\u8bc1\u670d\u52a1\u5668\u53ef\u4ee5\u65f6\u523b\u76d1\u542c\u5ba2\u6237\u7aef\u8fde\u63a5\u7684\u5efa\u7acb\uff0c\u63d0\u9ad8\u4e86\u5904\u7406\u6027\u80fd\u3002<\/p>\n<p>&nbsp;<\/p>\n<h5 id=\"id-\u6a21\u677f-\u53c2\u8003\u94fe\u63a5\uff1a\">\u53c2\u8003\u94fe\u63a5\uff1a<\/h5>\n<ul>\n<li><a href=\"https:\/\/blog.csdn.net\/yjp19871013\/article\/details\/82555417\">golang TCP Socket\u7f16\u7a0b<\/a><\/li>\n<li><a href=\"https:\/\/blog.csdn.net\/yjp19871013\/article\/details\/82711237\">\u5229\u7528golang\u901a\u9053\u4f18\u5316TCP Socket\u670d\u52a1\u5668<\/a><\/li>\n<li><a href=\"https:\/\/www.cnblogs.com\/liuzhongchao\/p\/9395027.html\">Golang Socket\u7f16\u7a0b<\/a><br \/>\n<a href=\"https:\/\/github.com\/astaxie\/build-web-application-with-golang\/blob\/master\/zh\/08.1.md\">https:\/\/github.com\/astaxie\/build-web-application-with-golang\/blob\/master\/zh\/08.1.md<\/a><\/li>\n<li><a href=\"http:\/\/tonybai.com\/2015\/11\/17\/tcp-programming-in-golang\/\">Go\u8bed\u8a00TCP Socket\u7f16\u7a0b<\/a><br \/>\n<a href=\"https:\/\/github.com\/bigwhite\/experiments\/tree\/master\/go-tcpsock\">https:\/\/github.com\/bigwhite\/experiments\/tree\/master\/go-tcpsock<\/a><\/li>\n<li><a href=\"https:\/\/www.secpulse.com\/archives\/65730.html\">golang\u4e4bTCP\u5f00\u53d1<\/a><\/li>\n<li><a href=\"https:\/\/golang.org\/pkg\/net\/#example_Listener\">https:\/\/golang.org\/pkg\/net\/#example_Listener<\/a><br \/>\n<a href=\"https:\/\/golang.org\/pkg\/net\/#TCPAddr\">https:\/\/golang.org\/pkg\/net\/#TCPAddr<\/a><br \/>\n<a href=\"https:\/\/golang.org\/pkg\/net\/#Dial\">https:\/\/golang.org\/pkg\/net\/#Dial<\/a><br \/>\n<a href=\"https:\/\/golang.org\/pkg\/net\/#Listen\">https:\/\/golang.org\/pkg\/net\/#Listen<\/a><\/li>\n<\/ul>\n<p>=END=<\/p>\n","protected":false},"excerpt":{"rendered":"<p>=Start= \u7f18\u7531\uff1a \u5b66\u4e60\u3001\u6574\u7406\u4e00\u4e0b\u5982\u4f55\u7528Go\u8bed\u8a00\u8fdb\u884cTCP socket\u7f16\u7a0b\uff0c\u65b9\u4fbf\u4ee5\u540e\u9700\u8981\u7684\u65f6\u5019\u8fdb\u884c\u53c2\u8003\u548c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23,7,12],"tags":[564,173,1171],"class_list":["post-4169","post","type-post","status-publish","format-standard","hentry","category-knowledgebase-2","category-programing","category-tools","tag-golang","tag-socket","tag-tcp"],"views":5153,"_links":{"self":[{"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/posts\/4169","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/comments?post=4169"}],"version-history":[{"count":1,"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/posts\/4169\/revisions"}],"predecessor-version":[{"id":4170,"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/posts\/4169\/revisions\/4170"}],"wp:attachment":[{"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/media?parent=4169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/categories?post=4169"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ixyzero.com\/blog\/wp-json\/wp\/v2\/tags?post=4169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}