标题:[实践成功]go tcp tcpclient编码 出处:向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除 时间:Wed, 30 Dec 2020 16:55:50 +0000 作者:jackxiang 地址:http://jackxiang.com/post/10815/ 内容: Server:echoServer.go /** * File: echoServer.go * Author: 蛇叔 * 公众号: 蛇叔编程心法(snakeCodeHeart) */ package main import ( "fmt" "net" "os" "syscall" ) const ( PORT = 8888 ADDR = "127.0.0.1" SIZE = 100 ) func main() { // 1. create socketfd socketFd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0) if err != nil || socketFd < 0 { fmt.Println("socket create err: ", err) os.Exit(-1) } // 2. bind addr and port ip4 := net.ParseIP(ADDR).To4() if ip4 == nil { fmt.Println("net.ParseIP err") os.Exit(-1) } sa := &syscall.SockaddrInet4{Port: PORT} copy(sa.Addr[:], ip4) err = syscall.Bind(socketFd, sa) if err != nil { fmt.Println("socket bind err: ", err) os.Exit(-1) } // 3. listen err = syscall.Listen(socketFd, 128) if err != nil { fmt.Println("socket listen err: ", err) os.Exit(-1) } // 4. accept acceptFd, _, err := syscall.Accept(socketFd) if err != nil { fmt.Println("socket accept err: ", err) os.Exit(-1) } var ( buf = make([]byte, SIZE) readn int err2 error ) for { // 5. read data readn, err2 = syscall.Read(acceptFd, buf) if err2 != nil { break } if readn > 0 { // 6. write data writen, _ := syscall.Write(acceptFd, buf[:readn]) if writen < 0 { fmt.Println("socket write err: ", err) break } } else if readn == 0 { fmt.Println("客户端已关闭") break } else if readn < 0 && err2 != nil { fmt.Println("socket read err: ", err2.Error()) break } } // 7. close _ = syscall.Close(acceptFd) _ = syscall.Close(socketFd) } Client:echoClient.go /** * File: echoClient.go * Author: 蛇叔 * 公众号: 蛇叔编程心法 */ package main import ( "bufio" "fmt" "net" "os" "syscall" ) const ( PORT = 8888 ADDR = "127.0.0.1" SIZE = 100 ) func main() { // 1. 建立socket socketFd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0) if err != nil || socketFd < 0 { fmt.Println("socket create err: ", err) os.Exit(-1) } ip4 := net.ParseIP(ADDR).To4() if ip4 == nil { fmt.Println("net.ParseIP err") os.Exit(-1) } sa := &syscall.SockaddrInet4{Port:PORT} copy(sa.Addr[:], ip4) // 2. 发起主动连接 err = syscall.Connect(socketFd, sa) if err != nil { fmt.Println("socket connect err: ", err) os.Exit(-1) } var ( bufReader = bufio.NewReader(os.Stdin) buf = make([]byte, SIZE) writen int readn int err2 error ) for { // 3. 从标准输入读取数据 line, _, err := bufReader.ReadLine() if err != nil { fmt.Println("bufReader.ReadLine err: ", err) break } buf = line[:] // 4. 向socket对端写入数据 writen, err2 = syscall.Write(socketFd, buf) if writen > 0 { readn, err2 =syscall.Read(socketFd, buf) if readn > 0 { fmt.Println("read from socket: ") fmt.Println(string(buf[:readn])) } else { break } } else if writen <= 0 && err2 != nil { fmt.Printf("socket write; writen:%d, err: %s\n", writen, err2) break } } // 5. close socketFd _ = syscall.Close(socketFd) } jackXiang@localhost  ~/golearning  ./echoClient jack read from socket: jack xiang read from socket: xiang Q:果然Ok,两个问题探讨下: 1) ip4 := net.ParseIP(ADDR).To4() sa := &syscall.SockaddrInet4{Port: PORT} copy(sa.Addr[:], ip4) #这个sa.Addr[:] 冒号啥写法呢? 2)for { 这里面是epoll 吗?} A: 1. copy(sa.Addr[:], ip4) #这个sa.Addr[:] 冒号啥写法呢? sa.Addr 是一个数组, sa.Addr[:] 将这个数组临时转为切片,底层数组指向sa.Addr数组 方便copy进行切片复制 2. 就是个for{}死循环,防止代码往下执行 来自: https://mp.weixin.qq.com/s/dRADQ5kUCT80dX7oEAAXyA https://mp.weixin.qq.com/s/kFHw73w_IIqjKeicesCpZw Generated by Jackxiang's Bo-blog 2.1.1 Release