2013-01-12 53 views
0

我已经写下面这基本上产生一个单独的线程,用于接收然而,数据被写入在主线程的数据多线程TCP客户端的接近()'发送只在标准输入上接受了来自用户的输入。TCP FIN不做一个多线程TCP客户端

现在,在按下CTRL^d再执行出来的循环(围绕函数getline()调用),并关闭套接字描述符,但没有FIN看到在电线上。但是,使用shutdown()替换close()会有所作为。关闭()关闭时FIN没有发送,但关闭(fd,SHUT_WR)FIN是在线上发送的?

为什么这种差异?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <errno.h> 

void *receiver (void *arg); 

pthread_t thrid; 

int sockfd; 

int reUse = 0; 

int 
main (int argc, char *argv[]) 
{ 
    struct sockaddr_in servaddr; 

    struct sockaddr_in clntaddr; 

    char *line; 

    size_t len = 0; 

    size_t read; 

    int bytes; 

    if (argc < 6) 
    { 
     printf 
      ("Usage:%s <Server Ipv4 address> <Server Port> <SO_REUSEADDR Yes(1)/No(0))> <Close(0)/SHUT_RD(1)/SHUT_WR(2)/SHUT_RDWR(3)> <sleep (in sec)> [Client IPv4 address] [Client Port]\n", 
      argv[0]); 
     return -1; 
    } 

    /* 
    * AF_INET, AF_INET6, AF_UNIX, AF_NETLINK 
    * SOCK_STREAM (TCP), SOCK_DGRAM (UDP), SOCK_RAW 
    */ 
    if ((sockfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) 
    { 
     printf ("Failed to create socket: %s\n", strerror (errno)); 
     return -1; 
    } 

    /* 
    * set SO_REUSEADDR option for the UDP server socket 
    */ 
    reUse = atoi (argv[3]); 
    if (reUse) 
    { 
     int i = 1; 

     setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (void *) &i, 
        sizeof (i)); 
    } 

    bzero (&clntaddr, sizeof (struct sockaddr_in)); 

    if (argc == 8) 
    { 
     printf ("doing bind......\n"); 
     clntaddr.sin_family = AF_INET; 
     clntaddr.sin_port = htons (atoi (argv[7])); 
     inet_aton (argv[6], &clntaddr.sin_addr); 

     if (bind 
      (sockfd, (struct sockaddr *) &clntaddr, 
      sizeof (struct sockaddr_in)) == -1) 
     { 
      perror ("Failed to bind"); 
      close (sockfd); 
      return -1; 
     } 
    } 

    bzero (&servaddr, sizeof (struct sockaddr_in)); 

    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons (atoi (argv[2])); 
    inet_aton (argv[1], &servaddr.sin_addr); 

    if (-1 == 
     connect (sockfd, (struct sockaddr *) &servaddr, 
       sizeof (struct sockaddr_in))) 
    { 
     printf ("Failed to connect: %s\n", strerror (errno)); 
     return -1; 
    } 

    if (pthread_create (&thrid, NULL, receiver, NULL) < 0) 
    { 
     printf ("Failed to create thread\n"); 
    } 

    while ((read = getline (&line, &len, stdin)) != -1) 
    { 
     bytes = send (sockfd, line, len, 0); 
     if (bytes < 0) 
     { 
      if (errno == EINTR) 
       continue; 
      else 
       printf ("%Read error %s\n", pthread_self(), 
         strerror (errno)); 
     } 

    } 

    if (0 == atoi (argv[4])) 
    { 
     printf ("doing close()....\n"); 
     close (sockfd); 
    } 
    else if (1 == atoi (argv[4])) 
    { 
     printf ("doing shutdown(..., SHUTRD)....\n"); 
     shutdown (sockfd, SHUT_RD); 
    } 
    else if (2 == atoi (argv[4])) 
    { 
     printf ("doing shutdown(..., SHUTWR)....\n"); 
     shutdown (sockfd, SHUT_WR); 
    } 
    else if (3 == atoi (argv[4])) 
    { 
     printf ("doing shutdown(..., SHUTRDWR)....\n"); 
     shutdown (sockfd, SHUT_RDWR); 
    } 

    if (line) 
     free (line); 

    sleep (atoi (argv[5])); 
} 

void * 
receiver (void *arg) 
{ 
    char buff[512]; 

    int bytes; 

    while (1) 

    { 
     bytes = recv (sockfd, buff, sizeof (buff), 0); 
     if (bytes < 0) 
     { 
      if (errno == EINTR) 
       continue; 
      else 
       printf ("%Read error %s\n", pthread_self(), 
         strerror (errno)); 
      pthread_exit (-1); 
     } 
     else if (bytes == 0) 
     { 
      printf ("connection closed by Peer\n"); 
      close(sockfd); 
      pthread_exit (-1); 
     } 
     else 
     { 
      printf ("Msg Received:%s\n", buff); 
     } 
    } 
} 

回答

0

呼叫关机(WR)将发送FIN,但关闭有点不同:如果fd参考计数不等于0,则不会发送FIN。

+0

你的意思,因为插座是的recv()系统调用中使用一个单独的线程,因此其参考正在增加? –

+0

@VivekGupta这是不可预测的,因为有一个竞争条件。对'close'的调用可能在调用'recv'之前,之中或之后发生。 –

0

您可以使用shutdown(插座,SHUT_WR)之前关闭(插座)