工作的原因接触到socket,要使用socket实现一个长连接。之前只在C/C++上用过socket,而且在学校的时候也只是简单的做聊天室小程序,并没有涉及到长连接。突然用到工作项目上,心里还是有点悬的,毕竟网上的资料也不是很多。这里就一步一步记录下学习的过程、遇到的问题以及最重要的——解决问题的方法。
一、说明
golang中的socket需要用到net包,里面封装好了很多常用的函数方法以及元素类型。而且无需像C一样要经历socket,bind,listen,accept等等流程,只需要简单的几步流程就能完成,非常方便。
二、IP类型
net包中定义的ip类型直接就是byte数组:
1 | type IP []byte |
我们可以使用func parseIP(s string) IP
来把一个ip地址转换成IP类型:
1 | ipAddr := "192.168.1.79" |
三、函数
3.1 funcResolveTCPAddr(net, addr string) (*TCPAddr, error)
ResolveTCPAddr
函数的功能是解析TCP连接的地址,包含ip
和port
net
:tcp
tcp4
tcp6
三选一,分别表示TCPv4,TCPv6和任意,默认是tcp4
addr
:主机的地址,可以是[ip+port]
,也可以是[domain+port]
,可以省略主机部分,表示本机地址
返回一个*TCPAddr
类型 ,表示一个TCP连接地址:
1 | type TCPAddr struct { |
3.2 func ResolveIPAddr(net, addr string) (*IPAddr, error)
ResolveIPAddr
函数的功能是解析ip地址:
net
:ip
ip4
ip6
分别代表IPv4,IPv6以及任意。默认留空表示ip4
addr
:IP地址 返回一个*IPAddr
结构:
1 | type IPAddr struct { |
3.3 func Dial(network, address string) (Conn, error)
Dial
函数的功能是建立一个连接:
network
: 如果是TCP连接,对应tcp
tcp4
tcp6;如果是IP连接,对应ip ip4 ip6
。对于ip连接,需要在后面加一个冒号然后注明协议号或者协议名字address
:连接的地址,ip+port
或domain+port
形式,也可以省略主机地址表示本地地址217.0.0.1
返回一个net.Conn
接口对象,包含了连接的信息,我们可以使用该对象的Write()
和Read()
对连接进行读写。
1 | type Conn interface { |
与这个函数相对应的两个函数:
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error)
分别表示建立TCP请求和IP请求,中间多的laddr
表示本地的地址,一般为nil
。
3.4 func (c *conn) Write(b []byte) (int, error)
向conn
连接对象中写入数据,即发送数据给对方,写入的数据是[]byte
类型,成功将返回发送的数据包字节数。
1 | n, err := tcpCoon.Write([]byte("HelloWorld")) |
3.5 func (c *conn) Read(b []byte) (int, error)
从conn连接对象中读取数据,成功将返回读取到的字节数。
1 | recvData := make([]byte, 2048) |
3.6 func Listen(net, laddr string) (Listener, error)
Listen函数在服务端使用,让服务端开始监听。
net
:和上面一样,可以是tcp
ip
相关的值laddr
:要监听的地址,ip+port
省略主机地址将使用本机地址127.0.0.1
相应的两个函数:
func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error)
:监听TCP连接func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error)
:监听IP连接
3.7 func (l *TCPListener) Accept() (Conn, error)
服务端开始监听需要使用Accept
函数来接受客户端连接,此时服务端将进入阻塞状态。
相应的还有一个
func (l *TCPListener) AcceptTCP() (*TCPConn, error)