LINUX TCP相关

来源:互联网 发布:python 逐行读取txt 编辑:程序博客网 时间:2024/05/29 14:29

http://machael.blog.51cto.com/829462/211989/


http://blog.chinaunix.net/uid-8489474-id-2031032.html


http://www.cnblogs.com/jiangz/p/3307906.html


?????SO_LINGER

http://www.2cto.com/net/201209/157585.html   FFD


http://blog.csdn.net/lgp88/article/details/7176509


http://blog.chinaunix.net/uid-22412952-id-2150041.html  信号驱动IO

http://www.t086.com/article/4792


linux tcp api, socket, TCP信令之前的联说明:

   1.   connect()  ------------------>syn to server

    2.   recv()  返回值:>0: 接收到tcp数据, =0:对端调用了shutdown,  <0: error

    3.   listen() 如果服务器端没用对特定的端口地址进行listen(即便已经经过socket  bind),

                        connect: 会得到错误(Connection refused), 客户端会收到对端发来的TCP信令(RST)。

                        即当一个端口没有做为TCP的监听端口时,会发生连接拒绝(TCP层的拒绝)。

                        只要listen过, 那TCP层就会接收一个连接请求。而accept只是把连接请求接管到应用层,可以理解为TCP层与应用层的接口。

                       listen不阻塞,它其实只是对TCP和socket的配置,将socket挂在tcp的一个端口上,这样TCP就有了理由接收tcp连接请求(TCP认为有了接收点,接收才有意义)。



????wireshark如何得到一个tcp包是keepalive包, wireshark的信息得到keepalive的识别是在SEQ/ACK字段,所以应该是通过seq/ack得到的,具体FFD。



场景1:

    server端: listenfd绑定端口,然后监听此端口, sleep(10)的目的是可以有连接请求到来,然后退出。

                        因为如前所述listen只是配置,配置完之后,TCP层就可以接收连接请求,故需要sleep一下,且此操作不会影响TCP对连接请求的接收。

                       此场景只是为了说明listenfd的表现。

 70 if(bind(listenfd,(struct sockaddr *)addr,addrLen)<0) 71     { 72         perror("bind error"); 73         return -1; 74     } 75     if(listen(listenfd,LENGTH_OF_LISTEN_QUEUE)<0) 76     { 77         perror("listen error"); 78         return -1; 79     } 80     sleep(10); 81     exit(1);

     client端:进行两次用同socket(同端口)对服务端进行connect.

60     if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)    )==-1) 61     { 62         printf("connect fail, err:%s\n", strerror(errno)); 63         //exit(1); 64     } 65     cout<<"begin to connect again"<<endl; 66     if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)    )==-1) 67     { 68         printf("connect fail, err:%s\n", strerror(errno)); 69         //exit(1); 70     } 71     for(;;) 72     { 73  74     }
       首先对connect与listen这一对函数进行说明:

                       可以认为这一对函数只是在对TCP层进行操作(或者说配置)。

              listen是配置TCP层进行TCP连接请求的接收,接收队列也是在TCP层来维护(当然,应用层配置了其队列的大小)。

              connect是让TCP层进行一次TCP连接请求。

       情况1:服务器端关闭(对TCP层来说准确的是,TCP服务端没有连接点。 bind是socket与地址的绑定, listen是socket与TCP的联系)

               结论:与场景2一致。

       情况2:服务器端开启(只到listen), 最后直接exit(1),客户端去连接会发生什么呢?(客户端从同一socket连接两次)

                 

     

  结论:1. 服务器端只listen(配置了TCP接收连接),应用层并没有accept的情况下,当服务器端退出(exit(1)),在tcp层服务器端会向客户端发送RST。

                             可见RST的一层意思是连接请求没有被应用层接收(accept)。没有被应用层接收的意思很多,包括TCP服务端不存在,TCP接收了请求但应用层没有接收等。

                            暂认为连接请求只要没到达应用层(ACCEPT),TCP服务端就会发送RST给客户端。

                            2. 客户端发送了两次连接请求(使用同样的端口SOCKET),可以看到第一次连接请求TCP层握手成功。而第二次的连接请求没有发出去。

                                第二次的连接connect得到ERRNO: Transport endpoint is already connected。说明一个连接点如果已经连接上了,那就不可以再次用它建立连接。

          情况3:作为情况2的延续,服务器端不直接退出,先调用shutdown(listenfd), sleep(5)(保证shutdown触发的TCP通信流程结束),再exit(1)。客户端去连接会发生什么呢?(客户端从同一socket连接两次)

                 结论:wireshark上的表现与情况2相同。也是RST。       RST的意思:1连接拒绝, 2.发端socket关闭读。 当一方接收到RST, recv函数将返回值0.

                            不同的是,情况2RST的产生是由exit(1)造成的,而情况3RST的产生是由shutdownt造成的。实际上RST是由SHUTDOWN(fd, SHUT_RD)导致的。


           情况4:client端在connect之前设置socket非阻塞,不启动server端


              两次调用connect,只有一次的流程,因为是非阻塞,第一次调用connect,立即返回errno:Operation now in progress  操作进行中,server侧的TCP层收到SYN后发回RST,但因为connect已经返回,不会处理RST,第二次调用connect时,此时的connect会处理RST,所以在非阻塞的情况下,两次connect完成了一次握手尝试。

            情况5: server端在listen后,立即调用shutdown(listenfd, SHUT_RD)

                

               即拒绝。

               

             情况5: server端在listen后,立即调用shutdown(listenfd, SHUT_WR)

                 握手成功。

             情况6: 如果一端关闭了读shut_down(fd, SHUT_RD),则会发送RST给对端,那对端怎么得到对方已经关闭了读呢?两个方式,1.本端recv到RST时,会返回-1,err为:

                            Connection reset by peer。 之后如果在recv此socket,会返回0.  2.如果之前没有recv到RST,而send时发现socket被RST,则send时会返回-1, err为:Connection reset by peer。在本端recv到RST后或send时发现了rst之后, 再send此socket时,内核会发SIGPIPE信号过来,默认程序会退出。

              情况5及6的总结:关于shutdown函数,shutdown函数与TCP消息RST有密切的关系,shutdown RD,才会产生向对方发送RST, shutdown WR不会产生向对方发送RST.                                                当调用shutdown WR时,对于TCP层,会发送FIN, 本端再send时,内核会发送BROKEN PIPE给进程。

            


场景2:

       服务器端没有bind, 直接进行listen操作。客户端去连接会发生什么呢?(客户端从同一socket连接两次)


       可以看到信令从服务器所在主机发回两个RST。

       客户端的connect函数会得到ERRNO: Connection refused。因为TCP服务端连接点不完整,缺少地址,也就是客户端要连接的地址没有与TCPsocket建立连接(个人说法)。


TCP定时器:

       1. 连接建立定时器:在发送syn后等待ACk,如果超时,连接建立将中止

       2. 重传定时器:发送TCP数据段后等待ACK,如果超时,重传TCP数据段。重传定时器的值 (即TCP等待对端确认的时间)是动态计算的,与RTT的估计值密切相关,且还取决于该报文段已被重传的次数。

   3. 延迟ACK定时器:在一端收到必须确认但不必马上确认的TCP数据段时,启动此定时器,在超时时间内,确认消息可以随发送数据一起发送给对端,如果超时,当关闭此定时器,且需要发送一个立即确认ACK。

      4. 持续定时器:

      5. 保活定时器:连接在空闲达到保活定时器设定的时间后(即起时),会对对端进行连接测试。

      6. 

           

0 0
原创粉丝点击