Go socket编程

前端之家收集整理的这篇文章主要介绍了Go socket编程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

socket

   socket应该是各种语言中网络编程的基础,它介于应用层与传输层之间,只要学会使用它的接口即可。

TCP

   以下建立两台机器互相通信。

Server

   以下是Go语言中通过socketgoroutine编写的一个非常简单的服务端。

   流程如下:

   建立与服务端的链接

   进行数据收发

   关闭链接

// D:\GoLeran\src\yunya.com\TCPServer>

package main

import (
	"bufio"
	"fmt"
	"net"
	"strings"
)

func main(){
	listen,err := net.Listen("tcp","127.0.0.1:9999")
	if err != nil {
		fmt.Println("listent Failed,err:",err)
		return
	}
	for {
		conn,err := listen.Accept() // 建立链接
		if err != nil {
			fmt.Println("accept Failed,err) // 三次握手失败
			continue
		}
		go process(conn) // 启动多个goroutine来处理回复
	}
}

// 处理请求
func process(conn net.Conn) {
	defer conn.Close() // 关闭链接通道
	for {
		reader := bufio.NewReader(conn)
		var buf [1024]byte
		n,err := reader.Read(buf[:]) // 读取数据 读取的字节数,错误信息
		if err != nil {
			fmt.Print("read form client Failed,err)
			break
		}
		recvStr := string(buf[:n])
		fmt.Println("client message:",recvStr)
		var inputMsg string
		fmt.Println("请输入你要发送的信息:")
		fmt.Scanln(&inputMsg)
		inputMsg = strings.Trim(inputMsg,"\r\n") // 去除空行等,防止阻塞
		conn.Write([]byte(inputMsg))
	}
}

Client

   以下是客户端的代码

   建立与服务端的链接

   进行数据收发

   关闭链接

D:\GoLeran\src\yunya.com\TCPClient>

package main

import (
	"fmt"
	"net"
	"strings"
)

func main() {
	conn,err := net.Dial("tcp","127.0.0.1:9999") // 绑定服务端地址
	if err != nil {
		fmt.Println("err:",err)
		return
	}
	defer conn.Close() // 关闭双向链接
	for {
		var inputMsg string
		fmt.Println("请输入你要发送的信息:")
		fmt.Scanln(&inputMsg)
		inputMsg = strings.Trim(inputMsg,"\r\n") // 去除空行等,防止阻塞
		if strings.ToUpper(inputMsg) == "quit" {
			return
		}
		_,err = conn.Write([]byte(inputMsg)) // 发送数据
		if err != nil {
			return
		}
		buf := [512]byte{}
		serverMsg,err := conn.Read(buf[:]) // 服务端返回的信息
		if err != nil {
			fmt.Println("recv Failed err:",err)
			return
		}
		fmt.Println("server message:",string(buf[:serverMsg]))
	}
}

UDP

Server

   UDP不用建立双向链接,消息不可靠。因此一般来说使用较少。

// UDP/server/main.go

// UDP server端
func main() {
	listen,err := net.ListenUDP("udp",&net.UDPAddr{
		IP:   net.IPv4(0,0),Port: 30000,})
	if err != nil {
		fmt.Println("listen Failed,err)
		return
	}
	defer listen.Close()
	for {
		var data [1024]byte
		n,addr,err := listen.ReadFromUDP(data[:]) // 接收数据
		if err != nil {
			fmt.Println("read udp Failed,err)
			continue
		}
		fmt.Printf("data:%v addr:%v count:%v\n",string(data[:n]),n)
		_,err = listen.WriteToUDP(data[:n],addr) // 发送数据
		if err != nil {
			fmt.Println("write to udp Failed,err)
			continue
		}
	}
}

Client

   客户端代码如下:

// UDP 客户端
func main() {
	socket,err := net.DialUDP("udp",nil,})
	if err != nil {
		fmt.Println("连接服务端失败,err:",err)
		return
	}
	defer socket.Close()
	sendData := []byte("Hello server")
	_,err = socket.Write(sendData) // 发送数据
	if err != nil {
		fmt.Println("发送数据失败,err:",err)
		return
	}
	data := make([]byte,4096)
	n,remoteAddr,err := socket.ReadFromUDP(data) // 接收数据
	if err != nil {
		fmt.Println("接收数据失败,err:",err)
		return
	}
	fmt.Printf("recv:%v addr:%v count:%v\n",n)
}

TCP粘包

解决方

   由于TCP是流式传输协议。所以可能会产生粘包现象,我们需要划分每次数据的大小边界,所以可以自定制一个收发消息的协议。如下:

// socket_stick/proto/proto.go
package proto

import (
	"bufio"
	"bytes"
	"encoding/binary"
)

// Encode 将消息编码
func Encode(message string) ([]byte,error) {
	// 读取消息的长度,转换成int32类型(占4个字节)
	var length = int32(len(message))
	var pkg = new(bytes.Buffer)
	// 写入消息头
	err := binary.Write(pkg,binary.LittleEndian,length) // 小端排列,排列方式从左至右。详情搜索大小端排列
	if err != nil {
		return nil,err
	}
	// 写入消息实体
	err = binary.Write(pkg,[]byte(message))
	if err != nil {
		return nil,err
	}
	return pkg.Bytes(),nil
}

// Decode 解码消息
func Decode(reader *bufio.Reader) (string,error) {
	// 读取消息的长度
	lengthByte,_ := reader.Peek(4) // 读取前4个字节的数据
	lengthBuff := bytes.NewBuffer(lengthByte)
	var length int32
	err := binary.Read(lengthBuff,&length)
	if err != nil {
		return "",err
	}
	// Buffered返回缓冲中现有的可读取的字节数。
	if int32(reader.Buffered()) < length+4 {
		return "",err
	}

	// 读取真正的消息数据
	pack := make([]byte,int(4+length))
	_,err = reader.Read(pack)
	if err != nil {
		return "",err
	}
	return string(pack[4:]),nil
}

猜你在找的Go相关文章