Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
213 views
in Technique[技术] by (71.8m points)

c - TCP FIN not sent on doing 'close ()' for a multi-threaded TCP client

I have written below multi-threaded TCP client which basically spawns a separate thread for receiving the data however the data is being written in the main thread only having taken input from the user on standard input.

Now, having pressed ctrl^D then implementation comes out of the loop (around the getline () call) and closes the socket descriptor but no FIN is seen on the wire. However, replacing close() with shutdown () makes a difference. With close() no FIN is sent on the wire but with shutdown(fd, SHUT_WR) FIN is sent on the wire?

Why is this 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]
",
             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
", 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......
");
        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
", strerror (errno));
        return -1;
    }

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

    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
", pthread_self (),
                        strerror (errno));
        }

    }

    if (0 == atoi (argv[4]))
    {
        printf ("doing close()....
");
        close (sockfd);
    }
    else if (1 == atoi (argv[4]))
    {
        printf ("doing shutdown(..., SHUTRD)....
");
        shutdown (sockfd, SHUT_RD);
    }
    else if (2 == atoi (argv[4]))
    {
        printf ("doing shutdown(..., SHUTWR)....
");
        shutdown (sockfd, SHUT_WR);
    }
    else if (3 == atoi (argv[4]))
    {
        printf ("doing shutdown(..., SHUTRDWR)....
");
        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
", pthread_self (),
                        strerror (errno));
            pthread_exit (-1);
        }
        else if (bytes == 0)
        {
            printf ("connection closed by Peer
");
            close(sockfd);
            pthread_exit (-1);
        }
        else
        {
            printf ("Msg Received:%s
", buff);
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Call shutdown(WR) will send FIN,but close have little different:if fd reference count not equal 0 will not send FIN.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...