网络编程(10)—— 通过设置可选项取消socket的TImeWait状态以及开启Nagle算法

来源:互联网 发布:支付宝绑定淘宝账号 编辑:程序博客网 时间:2024/04/29 22:09

一、Time_Wait状态。

        我们先回顾一下之前学过的socket断开连接时的四次握手过程:
第一次握手:主机A向主机B发送FIN,提出断开连接的请求。
第二次握手:主机B接收到请求后向主机A传递ACK
第三次握手:主机B端向主机A发送FIN.
第四次握手:主机A向主机B发送ACK

        发起断开连接请求的主机A在完成第四次握手之后,会进入Time_Wait状态,此时其并没有完全的断开连接,而是在一段时间内保持Time_Wait状态。目的主要是防止第四次握手的数据包丢失,没有传递到主机B时,B会重新传递第三次握手的FIN,而此时保持在Time_Wait状态的主机A会重新发送第四次握手的数据包以保证主机B也能正常的断开连接。

        socket在TImeWait状态时,由于已经占用了端口号,当前端口号无法在这段时间内被重复使用.这就是我们有时候用Ctrl+C强制停止和客户端连接过的服务器端时,发生在启动服务器会出现bind error的现象的原因。因为谁发起断开连接的请求谁就会在第四次握手结束后进入Time_Wait的状态。当我们使用Ctrl+C强制停止服务器端的连接时,服务器会向客户端发起断开连接的请求,当进入Time_Wait状态后,此时的端口仍被服务器的socket占据着,因此我们重新服务器时运来的断开会出现bind error的现象。

        可以使用setsockopt函数设置Time_Wait状态下是否将端口重新分配给新的套接字。
opelen=sizeof(option);option=1;setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&option,optlen);

option=1,设置Time_Wait状态下将可将端口号重新分配给新的套接字。

option=0,缺省值,设置Time_Wait状态下将不可将端口号重新分配给新的套接字。

注意:设置时一定要在bind之前设置才会生效!!!!


二、Nagle算法


        Nagle算法应用于TCP层,是为了解决数据包过多而发生网络过载的问题。它的原理很简单,以传递一个字符串hello为例:
        未使用Nagle算法时:
        主机A向主机B传递“hello”时,不管主机B有没有回应,依次传递‘h’、‘e’、‘l’、‘l’、‘o’(这里是极端情况,实际上传送时不会一个字节一个字节的传送),这样算上主机B回给主机A的包共用了10个数据包;
        使用Nagle算法时:
        主机A向主机B传递“hello”时,先传一个‘h’,此时主机A会最大限度的进行缓冲,当收到主机B发回的‘h’的ACK消息时,将缓存的数据‘ello’一起发送给主机B,这样通过4个数据包就完成了发送任务。
       在默认情况下,socket在通信时是使用Nagle算法的,我们可以使用setsockopt函数改变这一设置:

opelen=sizeof(option);option=1;setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(void*)&option,optlen);
option=1,缺省值,开启Nagle算法。

option=0,关闭Nagle算法。

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<arpa/inet.h>#include<sys/socket.h>#include<linux/tcp.h>#define TRUE 1#define FLASE 0void error_handling(char* message);int main(int argc,char* argv[]){    int serv_sock,clnt_sock;    char message[30];    struct sockaddr_in serv_addr,clnt_addr;    int clntAdrLen,strLen,optlen,option;    if(argc!=2)    {        printf("Usage %s <port>\n",argv[0]);        exit(1);    }        //创建socket    serv_sock=socket(AF_INET,SOCK_STREAM,0);    if(serv_sock==-1)            error_handling("socket error");        //设置Time_Wait状态下套接字可重新分配    optlen=sizeof(option);    option=TRUE;    setsockopt(serv_sock,SOL_SOCKET,SO_REUSEADDR,(void*)&option,optlen);    //设置Nagle算法禁用    optlen=sizeof(option);    optlen=TRUE;    setsockopt(serv_sock,IPPROTO_TCP,TCP_NODELAY,(void*)&option,optlen);    //准备通信地址    memset(&serv_addr,0,sizeof(serv_addr));    serv_addr.sin_family=AF_INET;    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);    serv_addr.sin_port=htons(atoi(argv[1]));    //socket和通信地址的bind    if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))!=0)        error_handling("bind error");        //监听    if(listen(serv_sock,5)==-1)            error_handling("listen error");        //接收连接    clntAdrLen=sizeof(clnt_addr);    clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr,&clntAdrLen);        //读取数据    while((strLen=read(clnt_sock,message,sizeof(message)))!=0)    {        printf("sizeof(message) = %d\n",sizeof(message));        printf("接收到的数据是:%s 数据长度:%d\n",message,strLen);        write(clnt_sock,message,strLen);        //write(1,message,strLen);        fputs("回送成功。",stdout);        fputc('\n',stdout);    }        close(clnt_sock);    close(serv_sock);    return 0;}void error_handling(char* message){    fputs(message,stderr);    fputc('\n',stderr);    exit(1);}


Github位置:

https://github.com/HymanLiuTS/NetDevelopment

克隆本项目:

git clone git@github.com:HymanLiuTS/NetDevelopment.git

获取本文源代码:

git checkout NL10

1 0
原创粉丝点击