通过golang实现Tcp的连接与信息传输
本文主要介绍Tcp协议以及如何使用golang来建立一个简单的tcp连接服务,并且实现信息的传输。
Tcp协议是传输层的一个可靠数据传输协议,Tcp协议有以下几个特点:
TCP在IP层提供的不可靠服务基础上实现的可靠数据传输服务,基于流水线机制。当有发送端的数据丢失后,接收端不会不予理睬,而是重新会发送给发送方一个信号,请求重新发送该数据报。以此来确保数据的可靠性传输。这里只作简单解释可靠数据传输的特点:
如果TCP通道建立之后,数据在发送过程中丢失。TCP将会触发快速重传机制,下面是快速重传机制的特点:
SYN
请求报文段给服务端,并告诉服务端自己的初始报文段序列号是多少。SYNACK
响应报文段并且把服务端初始报文段序列号和滑动窗口缓存空间大小给客户端表明我已经接到你的请求了。SYNACK
报文段后会答复一个ACK
报文段表明我已经收到,可以建立连接了。同时会根据接收到的服务端的滑动窗口缓存空间大小,分配一个同样大小的滑动窗口缓存空间用于发送。FIN_WAIT_1
的终止等待状态。TCP规定FIN报文段即使不携带数据,也要消耗一个序号。close_wait
状态(关闭等待状态)。此时TCP通知上层应用进程,客户端已经准备关闭了,这时候处于版关闭状态。这时如果向客户端发送数据,客户端仍然需要接收。这个状态需要维持一段时间,如果期间有数据需要发送就进行发送。等待整个CLOSE_WAIT
状态持续时间结束。FIN_WAIT_2
的终止等待状态,等待服务端是否还有数据需要进行发送。LAST_ACK
最后确认状态,等待客户端进行确认。TIME-WAIT
(时间等待状态)注意此时客户端并未关闭,而是经过2*MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB之后才进入CLOSED
状态。CLOSED
关闭状态,同样撤销掉了TCB之后就结束了这次的TCP连接。因此可以看出,(除非特殊情况)服务端关闭是要早于客户端的。主要分为3部分
net.Listen("tcp", "127.0.0.1:4399") (Listener, error)
listen.Accept() (Conn, error)
defer listen.Close()
注意defer
语句一定要写在错误处理之后。如果写在错误之前,一旦发生了错误,该连接就不会被生成,进而执行defer
语句的时候无法进行通道关闭。
package main import ( "fmt" "net" ) func handle(conn net.Conn) { defer conn.Close() var info [256]byte n, err := conn.Read(info[:]) if err != nil { fmt.Println("conn Read fail ,err = ", err) return } fmt.Println("client send info to server si : ", string(info[:n])) } func main() { // 1. 建立tcp连接监听通道 listen, err := net.Listen("tcp", "127.0.0.1:4399") if err != nil { panic(err) } // 3. 关闭监听通道 defer listen.Close() fmt.Println("server is Listening") for { // 2. 进行通道监听 conn, err := listen.Accept() if err != nil { panic(err) } // 启动一个协程去单独处理该连接 go handle(conn) } }
客户端和服务端一样,也分为三个部分
net.Dial("tcp", "127.0.0.1:4399") (Conn, error)
msg := "Hi, I am a client" conn.Write([]byte(msg))
defer conn.Close()
在这里我只做了简单的处理,将字符串转化为字符切片通过Write
的方式发送给了服务端,并且该过程只进行了一次。如果需要多次持续建立连接并且发送,需要主动开启一个for
循环,并且设置循环结束条件。
package main import "net" func main() { // 1. 建立访问通道 conn, err := net.Dial("tcp", "127.0.0.1:4399") if err != nil { panic(err) } defer conn.Close() msg := "Hi, I am a client" conn.Write([]byte(msg)) }