go
Go语言Socket编程教程
协议 | 定义 |
---|---|
TCP(传输控制协议) | TCP 的主要特征是它在设计上是一种可靠的协议。如果没有数据包交付的证据,TCP 将重新发送数据包。TCP 数据包可用于的一些任务是建立连接、传输数据、发送确认和关闭连接。 |
IP(互联网协议) | IP 协议遵循端到端原则,将所有网络智能置于端节点而不是中间节点。这种设计有利于降低网络复杂性而不是可靠性。出于这个原因,互联网协议不保证数据包在网络上的可靠传递。相反,IP 与 TCP 一起工作以通过网络可靠地传送数据包。 |
UDP(用户数据报协议): | UDP 提供了一种更简单的传输层协议实现,虽然不如 TCP 可靠,但速度要快得多。UDP 不提供错误检查、纠正或数据包重传,因此速度非常快。当速度比可靠性更重要时,通常选择 UDP 而不是 TCP。UDP 通常用于在线游戏、视频聊天和其他实时应用程序。 |
net
包
Go的
net
包为网络I/O提供了一个可移植的接口,包括TCP/IP、UDP、域名解析和Unix域套接字。在本指南中,您将使用此软件包创建TCP和UDP服务器以及客户端。
net.Dial()
和net.Listen()
返回的数据类型是实现了io.Reader
和io.Writer
接口的。所以我们可以像使用常规文件I/O函数操作一样从TCP/IP连接发送和接收数据。
相应函数
返回值 | 函数 |
---|---|
Listener | func Listen(network, address string) (Listener, error) • network 取值范围是{tcp , tcp4 (IPv4-only), tcp6 (IPv6-only), unix (Unix sockets),unixpacket }• address 定义服务器将侦听的服务器地址和端口号 |
UDPConn | func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) • 该方法用于创建UDP服务 • network 取值范围:{"udp", "udp4", "udp6"}• laddr 参数定义了服务器将侦听的服务器地址和端口号func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error) • 该方法用于创建UDP客户端 • network 取值范围:{"udp", "udp4", "udp6"}• laddr 是监听地址(服务器)。如果laddr 为 nil,则自动选择本地地址。• raddr 是响应地址(客户端)。如果raddr 的 IP 为 nil 或是未指定的 IP 地址,则取127.0.0.1。 |
UDPAddr | func ResolveUDPAddr(network, address string) (*UDPAddr, error) • 这个函数返回一个 UDP 端口定义指针• network 取值范围:{"udp", "udp4", "udp6"}• address 参数格式为host:port . 这个host是一个ip地址, 或者是一个可解析的域名。例如localhost |
TCPAddr | func ResolveTCPAddr(network, address string) (*TCPAddr, error) • 这个函数返回一个 TCP 端口定义指针• network 取值范围:{"tcp", "tcp4", "tcp6"}• address 参数格式为host:port . 这个host是一个ip地址, 或者是一个可解析的域名。例如localhost |
Conn | func Dial(network, address string) (Conn, error) • 返回一个使用指定网络协议连接到指定地址的连接 • network 取值范围:{"tcp","tcp4","tcp6","udp","udp4","udp6","ip","ip4","ip6","unix","unixgram","unixpacket"}• 当使用 TCP 或者ICP 网络协议时, address 参数格式为host:port . 这个host是一个ip地址, 或者是一个可解析的域名。例如localhost |
TCPConn | func ListenTCP(network string, laddr *TCPAddr) (*TCPConn, error) • 该方法用于创建TCP服务 • network 取值范围:{"tcp", "tcp4", "tcp6"}• laddr 参数定义了服务器将侦听的服务器地址和端口号func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) • 这个函数返回一个 TCP 连接指针• network 取值范围:{"tcp", "tcp4", "tcp6"}• laddr 是监听地址(服务器)。如果为 nil,则取默认值• raddr 是响应地址(客户端). 如果raddr 的 IP 为 nil 或是未指定的 IP 地址,则取127.0.0.1。 |
TCP demo
TCP 服务端
package main import ( "bufio" "fmt" "net" "os" "strings" "time" ) func main() { arguments := os.Args if len(arguments) == 1 { fmt.Println("Please provide port number") return } PORT := ":" + arguments[1] // tcp监听端口,返回一个监听指定端口的 监听 l, err := net.Listen("tcp", PORT) if err != nil { fmt.Println(err) return } defer l.Close() // 阻塞,接入连接时,返回一个 监听指定端口 的 连接。 c, err := l.Accept() if err != nil { fmt.Println(err) return } for { // 从连接中取数据,边界符号是回车 netData, err := bufio.NewReader(c).ReadString('\n') if err != nil { // 从连接中获取数据出错,打印异常,退出for循环,触发 l.close()方法,关闭TCP监听 fmt.Println(err) return } if strings.TrimSpace(string(netData)) == "STOP" { // 接收到 STOP 消息,退出for循环,触发 l.close()方法,关闭TCP监听 fmt.Println("Exiting TCP server!") return } // 打印接收到的数据 fmt.Print("-> ", string(netData)) // 获取当前时间,并将其格式化,写入连接返回给客户端 t := time.Now() myTime := t.Format(time.RFC3339) + "\n" c.Write([]byte(myTime)) } }
TCP客户端
package main import ( "bufio" "fmt" "net" "os" "strings" ) func main() { args := os.Args if len(args) == 1 { fmt.Println("Please provide host:port") return } CONNECT := args[1] // 使用 tcp 协议连接到指定地址 c, err := net.Dial("tcp", CONNECT) if err != nil { fmt.Println(err) return } for { // 获取指令台输入 reader := bufio.NewReader(os.Stdin) fmt.Println(">>>") // 获取数据,知道遇到回车符 text, _ := reader.ReadString('\n') // 根据格式说明符格式化数据并写入连接 fmt.Fprintf(c, text+"\n") // 读取 tfp服务 数据返回 message, _ := bufio.NewReader(c).ReadString('\n') fmt.Print("->: " + message) // 如果服务端返回 STOP ,退出for循环 if strings.TrimSpace(string(text)) == "STOP" { fmt.Println("TCP client exiting...") return } } }
UDP demo
UDP服务端
package main import ( "bufio" "fmt" "net" "os" "strings" ) func main() { args := os.Args if len(args) == 1 { fmt.Println("Please provide a host:port string") return } CONNECT := args[1] udpAddr, _ := net.ResolveUDPAddr("udp4", CONNECT) UDPConn, _ := net.DialUDP("udp4", nil, udpAddr) fmt.Printf("The UDP server is %sn", UDPConn.RemoteAddr().String()) defer UDPConn.Close() for { reader := bufio.NewReader(os.Stdin) fmt.Printf(">>>") // 以回车符作为分隔符获取数据 text, _ := reader.ReadString('\n') // 将数据加上回车符,转为字节数组 data := []byte(text+"\n") // udp连接写入数据 _, err := UDPConn.Write(data) if strings.TrimSpace(string(data)) == "STOP" { fmt.Println("Exiting UDP client!") return } if err != nil { fmt.Println(err) return } buffer := make([]byte, 1024) n, _, err := UDPConn.ReadFromUDP(buffer) if err != nil { fmt.Println(err) return } fmt.Printf("Reply: %s\n", string(buffer[0:n])) } }
UDP客户端
package main import ( "fmt" "math/rand" "net" "os" "strconv" "strings" "time" ) func main() { arguments := os.Args if len(arguments) == 1 { fmt.Println("Please provide a port number!") return } PORT := ":" + arguments[1] // 以 udp4 协议,解析获得udp地址 udpAddr, err := net.ResolveUDPAddr("udp4", PORT) if err != nil { fmt.Println(err) return } // 以 udp4 协议,监听udp地址,返回udp连接 udpConn, err := net.ListenUDP("udp4", udpAddr) if err != nil { fmt.Println(err) return } defer udpConn.Close() buffer := make([]byte, 1024) rand.Seed(time.Now().Unix()) for { // 从udp连接中读取数据至缓存数组,并打印 n, addr, err := udpConn.ReadFromUDP(buffer) fmt.Print("->", string(buffer[0:n-1])) // 如果客户端发送 STOP 消息,退出for循环,触发udpConn.Close(),关闭udp连接 if strings.TrimSpace(string(buffer[0:n])) == "STOP" { fmt.Println("Exiting UDP server!") return } // 获取1到10000的随机数格式化为字符串,构建返回数据 data := []byte(strconv.Itoa(rand.Intn(1000) + 1)) fmt.Printf("data: %s\n", string(data)) // udpConn返回data给udp客户端 _, err = udpConn.WriteToUDP(data, addr) if err != nil { fmt.Println(err) return } } }
UDP极简demo
为语法简洁省略错误判断与处理
udp-server
package main import ( "fmt" "net" ) func main() { ServerConn, _ := net.ListenUDP("udp", &net.UDPAddr{IP: []byte{0, 0, 0, 0}, Port: 10001, Zone: ""}) defer ServerConn.Close() buf := make([]byte, 1024) for { n, addr, _ := ServerConn.ReadFromUDP(buf) fmt.Println("Received ", string(buf[0:n]), " from ", addr) } }
udp-client
package main import "net" func main() { Conn, _ := net.DialUDP("udp", nil, &net.UDPAddr{IP:[]byte{127,0,0,1},Port:10001,Zone:""}) defer Conn.Close() Conn.Write([]byte("hello")) }
参考地址:
https://www.xpresservers.com/create-a-tcp-and-udp-client-and-server-using-go
https://haicoder.net/golang/golang-network.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律