• tcp三次握手的一些疑问


    提到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多路复用技术来实现。

    也可参考:https://www.jianshu.com/p/1f59ba05f851 

  • 相关阅读:
    解决Java POI导出大数据量Excel报错:java.lang.OutOfMemoryError: Java heap space
    Central Limit Theorem
    qmake 与 配置文件
    KubeSphere安装KubeEdge
    IBM MQ MQCSP
    <string类(上)>——《C++初阶》
    Java学习笔记4.6.3 格式化 - DateTimeFomatter类
    spring cloud实践
    程序设计题 2:双11抢宝计划
    spring5.0源码解析 Aop 01
  • 原文地址:https://blog.csdn.net/fengcai_ke/article/details/126564028