美文网首页
tcp三次握手的一些疑问

tcp三次握手的一些疑问

作者: 分享放大价值 | 来源:发表于2020-12-03 21:52 被阅读0次

    提到tcp的三次握手,网上可以搜到很多资料,大体都是类似的,比如下面这张图示,client和server端的状态转换,报文标志位看上去挺清晰的。


    image.png

    但是从源码角度看会有几个不一样的地方,比如
    a. 服务器端收到客户端的syn报文,回复syn+ack后,就会进入syn_recv状态吗?
    b. 服务器端的状态会从listen转换到 syn_recv,再到established吗?

    下面是看过源码后根据自己理解画的一张图


    image.png

    server收到client发送的syn报文后,为了防止syn攻击,会首先创建request_sock结构,保存到hash表中(半连接队列),而不是直接分配sock结构。可参考kernel代码中 request_sock和sock结构体的定义,sock比request_sock需要更多内存。然后发送syn+ack报文给client。

    如果client是正常连接的话,会发送ack报文给server,server收到后会进行判断,如果是正常ack报文,就会接受此连接,将request_sock从hash表删除,真正分配sock结构,并设置sock->sk_state为TCP_SYN_RECV,将sock结构赋给request_sock->sock后,将request_sock再次添加到另一个链表(全连接队列),后面又紧接着把sock->sk_state为TCP_ESTABLISHED,最后唤醒accept进程到全连接队列取出sock,由accept进程使用newsock和client进行数据传输。

    上面这种防止syn攻击的方式成为syn cache,还有另一个syn cookie,可参考函数tcp_v4_conn_request,这种方法不会保存任何信息就可以达到防攻击目的。

    接下来回答上面的两个问题,对于问题a,server从收到syn到再次收到ack的这段时间内,因为还没有分配sock结构,所以从代码看,是在收到ack后,分配sock才设置TCP_SYN_RECV。但是还是可以认为是TCP_SYN_RECV,可以通过查看cat /proc/net/tcp确认。
    对于问题b,server sock一直是处于listen状态的,收到新连接后,会分配新的sock,改变新sock的状态。

    堵塞函数
    socket编程中有如下几个堵塞函数,简单介绍一下
    a. connect
    调用connect后,kernel会自动发送syn报文发起tcp三次握手。这个调用默认是堵塞的,等待三次握手完成后,才会返回成功与否。
    b. accept
    accept等待从全连接队列接收新连接,如果全连接队列为空,就会一直堵塞等待,直到新连接到来。
    c. read/write
    读写数据默认也都是堵塞的。

    如果不想堵塞的话,可以使用select/poll/epoll等io多路复用技术来实现。

    相关文章

      网友评论

          本文标题:tcp三次握手的一些疑问

          本文链接:https://www.haomeiwen.com/subject/hcslwktx.html