持续整理更新中 https://bbs.gameres.com/thread_842984_1_1.html
一、TCP为什么是三次握手?
- 1、TCP是面向连接:双方需证明彼此有收发能力。第一次握手,客户端发送SYN连接请求,服务端收到后仅能判断
客户端有发送能力 ;第二次握手,服务端发送ACK,证明服务端有接受和发送能力 ;第三次握手,客户端发送ACK包,证明客户端有接受能力 。 - 2、防止失效链接传送给服务端:当客户端发送SYN包后,此包在网络节点发生滞留,在客户端重新发包建立连接并释放后到达服务端,服务端以为客户端的再次请求,向客户端发送ACK(
二次握手包 ),假如非三次握手,此时服务端就建立连接并等待client的数据,但现在的client并没有此行为,不会理睬服务端的ACK。 - 3、TCP是可靠的:TCP需要seq序列号来做可靠重传或接收,为避免连接复用无法分辨出seq是延时还是旧链接的seq,因此需要双方三次握手约定双方的ISN(初始seq序列号)。第一次握手,客户端发送自己ISN_C;第二次握手,服务端收到了客户端ISN_C,并发送服务端的ISN_S和确认ISN_C;完成二次握手后,服务端确认收到了客户端的,而客户端无法确认收到服务端的(客户端没发ack,服务端无法确认客户端是否确认收到了)。所以只有客户端->服务端是可靠的。
第2条,实际上客户端收到非期望的ACK包会发送RST报文中止连接 第3条,当连接断开重连后,TCP依靠ISN识别旧链接重发的包,确认机制是累加的,seq X的确认,表明seq X-1都被确认收到了
二、为什么建立连接是三次握手,关闭连接却是四次握手?
因为建立连接的二次握手时,服务端把SYN和ACK一起回复。但是关闭连接时,当Server端收到FIN报文时,Server端的报文可能并没有发完,此时又要回应客户端FIN报文,所以先回复一个ACK报文表明收到, 然后等到Server端报文都发送完了,才发送FIN报文。因此不能一起发送。故需要四步握手。
三、一次访问网页的过程
四、BIO、NIO、AIO
https://zhuanlan.zhihu.com/p/152247738 BIO例子【多个线程处理业务】
func main(){
listen, err := net.Listen("tcp", "0.0.0.0:4000")
if err != nil {
log.Fatal(err)
}
defer listen.Close()
for {
socket, err := listen.Accept()
if err != nil {
log.Fatal(err)
}
go process(socket)
}
NIO例子(由java例子改造,仅供理解不可运行)【一个线程处理多个业务】
type SocketChannel struct{
socket net.Conn
schannel chan
}
func(s *SocketChannel)Bind(proto, addr string) (sc *SocketChannel, err error) {
listen, err := net.Listen(proto, addr)
if err !=nil{
return nil, err
}
s.socket = listen
schannel = make([]net.Conn, 0, 10)
go func(){
for{
socket, err := listen.Accept()
if err == nil && socket !=nil{
s.schannel <- socket
}
}
}()
return
}
func (s *SocketChannel)Accept() net.Conn {
select{
case c := <-s.schannel:
return c
default:
return nil
}
}
func (s *SocketChannel)Close() {
s.socket.Close()
}
var socketArray = []net.Conn
func main(){
sc, err := net.Bind("tcp", "0.0.0.0:4000")
if err != nil {
log.Fatal(err)
}
defer sc.Close()
for {
socket := sc.Accept()
if socket !=nil{
socketArray = append(socketArray, socket)
}
for i:=0;i<len(socketArray);i++{
var buffer bytes.NewBuffer()
io.Write(socketArray, buffer)
if len(buffer) > 0 {
fmt.Println("接收到消息", string(buffer))
}else if len(buffer) == -1 {
socketArray.Remove(i);
fmt.Println("断开连接")
}
}
}
Epoll的底层实现
epoll_create():调用linux系统的内核函数epoll_create()创建epoll实例 epoll_wait():调用linux系统的epoll_wait等待文件描述符epfd(epoll实例)的事件。当socket收到数据后,操作系统的中断 程序调用回调函数会给epoll实例的事件就绪列表rdlist里添加该socket引用(这块是操作系统实现的),当程序执行到epoll_wait时,如果rdlist已经引用了socket,那么epoll_wait直接返回;若rdlist为空,阻塞进程。 epoll_ctl():处理事件绑定
中断是系统用来响应硬件设备请求的一种机制,操作系统收到硬件的中断请求,会打断正在执行的进程,然后调用内核中的中断处理程序来响应请求。例如c/s通信中,s网卡收到客户端数据,将触发操作系统中断程序,将事件放进就绪事件列表rdlist
进程阻塞为什么不占用CPU资源
内核接收网络数据全过程
为什么Kafka吞吐量如此高
https://www.jianshu.com/p/16500d06846a
|