Server端常用函数、接口:
Listen函数:func Listen(network, address string) (Listener, error)network:选用的协议:TCP、UDP, 如:“tcp”或 “udp”address:IP地址+端口号, 如:“127.0.0.1:8000”或 “:8000”Listener 接口:
type Listener interface {Accept() (Conn, error)Close() errorAddr() Addr
}Conn 接口:
type Conn interface {Read(b []byte) (n int, err error)Write(b []byte) (n int, err error)Close() errorLocalAddr() AddrRemoteAddr() AddrSetDeadline(t time.Time) errorSetReadDeadline(t time.Time) errorSetWriteDeadline(t time.Time) error
}
TCP-服务端实现:
func main() {// 指定服务器的通讯协议、ip、端口,Listen本身不做监听,这一步是创建了一个用于监听的Socketlisten, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen出错:", err)return}defer listen.Close()fmt.Println("服务器启动完毕,等待客户端连接")// 阻塞监听客户端连接请求,成功建立连接后会返回用于通信的Socketaccept, err := listen.Accept()if err != nil {fmt.Println("listen.Accept出错:", err)return}defer accept.Close()fmt.Println("服务器与客户端连接成功")// 读取客户端发动的请求buf := make([]byte, 4096)read, err := accept.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}// 接收数据后处理数据fmt.Println("服务器获取到:", string(buf[:read]))
}
Mac可以通过netcat进行测试:
TCP-客户端实现:
func main() {// 指定用户端的通讯协议、ip、端口,Listen本身不做监听,这一步是创建了一个用于监听的Socketdial, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Dial出错:", err)return}defer dial.Close()// 发送数据dial.Write([]byte("我是客户端"))// 接收服务器返回的数据buf := make([]byte, 4096)read, err := dial.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}// 接收数据后处理数据fmt.Println("客户端获取到:", string(buf[:read]))
}
TCP实现并发-服务器:
上面都是单机版的客户端通信,如果想要实现并发,需要使用Goroutine+循环实现
- 循环读取客户端发送的数据
- 如果客户端强制关闭连接需要做处理
- 客户端发送exit时
演示:
package mainimport ("fmt""net""strings"
)func main() {// 创建监听套接字listen, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen出错:", err)return}defer listen.Close()// 创建客户端连接请求fmt.Println("服务器启动成功,等待客户端连接!")for {accept, err := listen.Accept()if err != nil {fmt.Println("listen.Accept出错:", err)return}// 调用服务器和客户端通信的函数go HandlerConnect(accept)}
}func HandlerConnect(accept net.Conn) {defer accept.Close()// 获取客户端发送的数据// 获取连接客户端的网络地址addr := accept.RemoteAddr()fmt.Println(addr, "客户端连接成功!")buf := make([]byte, 4096)for {read, err := accept.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}fmt.Println("服务器读到数据:", string(buf[:read]))// 模拟服务器收到数据后,回发给客户端,小写转大写data := strings.ToUpper(string(buf[:read]))accept.Write([]byte(data))}
}
TCP实现并发-客户端:
演示:
package mainimport ("fmt""net""os"
)func main() {//主动发送连接请求dial, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("et.Dial出错了", err)return}defer dial.Close()// os.Stdin():获取用户键盘录入,go func() {str := make([]byte, 4096)for {read, err := os.Stdin.Read(str)if err != nil {fmt.Println("os.Stdin.Read出错了", err)continue}// 读到的数据写给服务器,读多少写多少dial.Write(str[:read])}}()buf := make([]byte, 4096)// 回显服务器发送的数据,转成大写for {read, err := dial.Read(buf)// read=0的说明对端关闭连接,如果关闭连接这里就不需要往下读数据了if read == 0 {fmt.Println("检测到服务端端已经断开连接!")return}if err != nil {fmt.Println("回显服务器发送的数据dial.Read出错了", err)return}fmt.Println("客户端读到服务器的回显数据", string(buf[:read]))}
}
UDP实现并发-服务器:
由于UDP是“无连接”的,所以,服务器端不需要额外创建监听套接字,只需要指定好IP和port,然后监听该地址,等待客户端与之建立连接,即可通信。
创建监听地址:
func ResolveUDPAddr(network, address string) (*UDPAddr, error)
创建监听连接:
func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error)
接收udp数据:
func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error)
写出数据到udp:
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)
演示:
package mainimport ("fmt""net"
)func main() {// 指定服务器的ip和端口,和TCP协议不一样,需要先写好再传给ListenUDP使用ServerAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8000")if err != nil {fmt.Println("net.ResolveUDPAddr err:", err)return}fmt.Println("服务器启动成功!")// 创建用户通信的SocketudpConnect, err := net.ListenUDP("udp", ServerAddr)if err != nil {fmt.Println("net.ListenUDP err:", err)return}defer udpConnect.Close()fmt.Println("服务器创建Socket成功!")// 读写客户端的数据buf := make([]byte, 4096)count := 0for {// 返回值:n int(读到的字节数), addr *UDPAddr(客户端的地址), err errorudpBytes, ConnectAddr, err := udpConnect.ReadFromUDP(buf)if err != nil {fmt.Println("udpConnect.ReadFromUDP err:", err)return}count++// 模拟处理数据fmt.Printf("服务器读到第%v条数据 %v :%s\n", count, ConnectAddr, string(buf[:udpBytes]))go func() {// 回写数据到客户端udpConnect.WriteToUDP([]byte("回写数据到客户端\n"), ConnectAddr)}()}
}
UDP实现并发-客户端:
package mainimport ("fmt""net""time"
)func main() {dial, err := net.Dial("udp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Dial出错:", err)return}defer dial.Close()for {// 发送数据dial.Write([]byte("我是客户端"))// 接收服务器返回的数据buf := make([]byte, 4096)read, err := dial.Read(buf)if err != nil {fmt.Println("accept.Read出错:", err)return}// 接收数据后处理数据fmt.Println("客户端获取到:", string(buf[:read]))time.Sleep(time.Second)}
}