2012-07-11 56 views
1

我编写了下面的代码,以便使echo服务器(我写入stdout的数据从我的PC移动到服务器并返回到我的PC)。在代码中,我在套接字中设置了SO_LINGER选项。所以,当我按下Ctrl键+ç其中造成client.cpp一个FIN发送到server.cpp的client.cpp的close()应该等待10秒的server.cpp的套接字发回FINSO_LINGER选项不会导致close()等待

但我发现的是,client.cpp立即执行完毕和后退出按Ctrl +ç按下甚至的close()funcion没有返回-1它应该有如果对方在l_linger提到的时间到期之前没有发送FIN(我确信服务器没有发送FIN或者它必须已经在tcpdump中列出)。服务器端没有发送FIN除非我按Ctrl + C在其终端人。直到我按下Ctrl键+服务器的终端基于C tcpdump的显示在屏幕截图:

突出显示的上述线是客户端的FIN。

client.cpp:

int main() 
{ 
    int clifd; 
    clifd=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); 
    sockaddr_in serv; 
    bzero(&serv, sizeof(serv)); 
    serv.sin_family=AF_INET; 
    serv.sin_port=htons(3345); 
    inet_aton("127.0.0.1", &(serv.sin_addr)); 

    linger lin; 
    unsigned int y=sizeof(lin); 
    lin.l_onoff=1; 
    lin.l_linger=10; 
    setsockopt(clifd,SOL_SOCKET, SO_LINGER,(void*)(&lin), y); 

    connect(clifd, (sockaddr*)(&serv), sizeof(serv)); 
    int n,m; 
    char data[100]; 
    char recvd[100]; 
    for(;;) 
    { 
     fgets(data, 100,stdin); 
     n=strlen(data); 
     cout<<"You have written "<<n<<endl; 

     if(n>0) 
     { 
      while(n>0) 
      { 
       m=write(clifd,data,n); 
       n=n-m; 
      } 
     } 

     n=read(clifd, recvd, 100); 
     cout<<"Server echoed back "<<n<<endl; 

     if(n>0) 
     { 
      while(n>0) 
      { 
       m=fputs(data,stdout); 
       cout<<"m is"<<m<<endl; 
       fflush(stdout); 
       n=n-m; 
      } 
      //cout<<data<<endl; 
     } 
    } 
    int z=close(clifd); 
    if(z==-1) 
     cout<<"close returned -1 "<<endl; ***//this doesn't get printed*** 
} 

server.cpp:

void reflect(int x) 
{ 
    int n; 
    int m; 
    char data[100]; 
    cout<<"Entered reflect function"<<endl; 

    for(;;) 
    { 
     n=read(x,data, 100); 
     cout<<"Client sent "<<n<<endl; 

     if(n>0) 
     { 
      while(n>0) 
      { 
       m=write(x,data,n); 
       n=n-m; 
      } 
      cout<<"Successfully echoed back to client"<<endl; 
     } 
    }//end of for loop 
} 

int main() 
{ 
    sockaddr_in serv; 
    bzero(&serv, sizeof(serv)); 
    serv.sin_family=AF_INET; 
    serv.sin_port=htons(3345); 
    inet_aton("127.0.0.1", &(serv.sin_addr)); 

    int servfd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    int x; 
    x=bind(servfd, (sockaddr*)(&serv), sizeof(serv)); 

    cout<<"Bind returned"<<x<<endl; //this displays x as 0 

    listen(servfd, 5); 
    sockaddr cli; 
    int connfd; 
    pid_t id=-1; 
    socklen_t siz=sizeof(cli); 
    for(;;) 
    { 
     if((connfd=accept(servfd, &cli, &siz))>=0) 
      id=fork(); 

     if(id==0) 
      reflect(connfd); 
     else 
      continue; 
    } 
} 

为什么客户端的close()不等待?

+1

为什么你认为'Ctrl + C'不会终止你的应用程序(因此不会让它有机会看到套接字被关闭)?您不会在您的客户端应用程序中捕获到SIGINT,并且您看到的“FIN”可能是由于套接字被应用程序“强行关闭”而“关闭”。 – Chad 2012-07-11 19:35:42

回答

1

因此,client.cpp的close()应该等待server.cpp套接字发回FIN。

这是不正确的。它应该等待所有的输出数据和输出的FIN被发送,或者定时器到期。没有任何声明可以让你期待它等待传入的FIN。

5

为什么客户端的close()没有在等待?

您不打电话给您的客户close()。紧接在您的close()呼叫之前的for循环从不退出,因此close()永远不会出现。

键入CTRL - 在控制台ç导致程序立即退出,而不执行任何余下的行动。

由于close()永远不会被调用,您的其余问题(应该close()等待?我应该使用closesocket()?等)是没有意义的。

如果你希望能够退出for(;;)循环,尝试这样的事情:

for(;;) 
{ 
    if(fgets(data, 100,stdin) == NULL) 
    break; 
    ... rest of loop goes here ... 

然后,当你运行你的客户端程序,不终止它CTRL - Ç ,而是键入CTRL - D作为唯一的字符就行了。

+1

您可以使用'signal.h'和一些状态标志来显示OP如何使这个关闭呼叫发生。 – Chad 2012-07-11 19:41:44

2

从MSDN上的linger引用(如果你不信任的MSDN,你可以找到相同的信息here

灵儿结构保持有关规定,插座应如何表现时,特定的信息插座数据排队等待发送,并在套接字上调用closesocket函数。

所以它会一直等到所有的数据被发送,直到收到一个FIN。

3

,就答案拓展上面,如果你想获得所谓的close()功能,使这些相对简单的客户端的变化:

​​

现在,当你发送一个SIGINT(通过Ctrl+C或通过kill -s INT )你的程序会优雅地停下来,你的函数将被调用。您可以从那里开始排除故障。

+0

+1,但您可能希望将“bool stop_now”设置为“volatile bool stop_now”? – mpontillo 2012-07-11 20:00:40

+0

优秀点。 – Chad 2012-07-11 20:21:26