TCP FIN is not sent when the close () function is executed for a multi-threaded TCP client

I wrote below a multi-threaded TCP client, which basically generates a separate stream for receiving data, however, data is written to the main stream, only accepting input from the user at standard input.

Now, by pressing ctrl ^ D, the implementation exits the loop (around the call to getline ()) and closes the socket descriptor, but FIN does not see on the wire. However, replacing close () with shutdown () does matter. With close (), FIN is not sent to the wire, but with shutdown (fd, SHUT_WR) FIN is sent by wiring?

Why is this a difference?

#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
source share
2 answers

Turning off the call (WR) will send FIN, but closing will be slightly different: if the reference counter fd is not 0, it will not send FIN.

0
source

you can use shutdown (socket, SHUT_WR) before closing (socket)

0
source

All Articles