Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 套接字描述符在执行';关闭()';对于多线程UDP客户端_C_Linux_Multithreading_Sockets_Udp - Fatal编程技术网

C 套接字描述符在执行';关闭()';对于多线程UDP客户端

C 套接字描述符在执行';关闭()';对于多线程UDP客户端,c,linux,multithreading,sockets,udp,C,Linux,Multithreading,Sockets,Udp,我在下面写了UDP客户端,它基本上产生了一个单独的线程来接收数据报,但是数据报只在主线程中发送。现在,在Linux发行版上按ctrl^D对UDP客户机进行后期实例化(“./udpClient 1”)后,实现将退出循环(围绕getline()调用)并关闭套接字描述符 我所观察到的是,尽管在描述符上调用了close,但直到客户端进程终止,并且在执行“netstat-an | grep udp”时仍然看到相关条目,描述符才会被释放。但是,如果我注释/删除代码以生成接收方线程,那么调用close()后套

我在下面写了UDP客户端,它基本上产生了一个单独的线程来接收数据报,但是数据报只在主线程中发送。现在,在Linux发行版上按ctrl^D对UDP客户机进行后期实例化(“./udpClient 1”)后,实现将退出循环(围绕getline()调用)并关闭套接字描述符

我所观察到的是,尽管在描述符上调用了close,但直到客户端进程终止,并且在执行“netstat-an | grep udp”时仍然看到相关条目,描述符才会被释放。但是,如果我注释/删除代码以生成接收方线程,那么调用close()后套接字描述符将立即释放

似乎套接字引用计数在生成一个单独的线程(基本上接收并阻塞所述套接字描述符)时会增加,因此close()调用什么也不做

如果套接字描述符在进程之间共享,而不是在线程之间共享,那么套接字引用计数会增加,这是需要的吗?这是因为Linux将线程实现为LWP吗?如果是,这是期望的行为吗

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

void *receiver (void *arg);

int sockfd;

int doConnect = 0;

int
main (int argc, char *argv[])
{
    pthread_t thrid;

    struct sockaddr_in servaddr;

    struct sockaddr_in clntaddr;

    char *line;

    size_t len = 0;

    size_t read;

    if (argc < 4)
    {
        printf
            ("Usage:%s <Server Ipv4 address> <Server Port> <Connect Yes(1)/No(0)> [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_DGRAM, IPPROTO_UDP)) == -1)
    {
        printf ("Failed to create socket: %s\n", strerror (errno));
        return -1;
    }

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

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

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

    /*
     * fill up the server details
     */
    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);

    doConnect = atoi (argv[3]);

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

    if (pthread_create (&thrid, NULL, receiver, NULL) < 0)
    {
        printf ("Failed to create thread: %s\n", strerror (errno));
        close (sockfd);
        return -1;
    }

    while ((read = getline (&line, &len, stdin)) != -1)
    {
        if (1 == doConnect)
        {
            if (send (sockfd, line, len, 0) < 0)
            {
                printf ("send () failed: %s\n", strerror (errno));
            }
        }
        else
        {
            if (sendto (sockfd, line, len, 0, (struct sockaddr *) &servaddr,
                        sizeof (struct sockaddr_in)) < 0)
            {
                printf ("sendto () failed: %s\n", strerror (errno));
            }
        }
    }

    if (line)
        free (line);

    close (sockfd);

    printf ("socket is closed.....\n");

    sleep (60);
}

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

    while (1)
    {
        memset (buff, 0, sizeof (buff));

        if (1 == doConnect)
        {
            if (recv (sockfd, buff, sizeof (buff), 0) < 0)
            {
                // printf ("recvfrom () failed: %s\n", strerror (errno));
                printf ("recv () failed\n");
            }
            else
            {
                printf ("recv () returned: %s\n", buff);
            }
        }
        else
        {
            if (recvfrom (sockfd, buff, sizeof (buff), 0, NULL, NULL) < 0)
            {
                // printf ("recvfrom () failed: %s\n", strerror (errno));
                printf ("recvfrom () failed\n");
            }
            else
            {
                printf ("recvfrom () returned: %s\n", buff);
            }
        }
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
无效*接收人(无效*参数);
int-sockfd;
int doConnect=0;
int
main(int argc,char*argv[])
{
pthread第三次;
servaddr中的结构sockaddr_;
clntaddr中的结构sockaddr_;
字符*行;
尺寸长度=0;
尺寸不可读取;
如果(argc<4)
{
printf
(“用法:%s[客户端IPv4地址][客户端端口]\n),
argv[0]);
返回-1;
}
/*
*AF_INET、AF_INET 6、AF_UNIX、AF_NETLINK
*SOCK_流(TCP)、SOCK_DGRAM(UDP)、SOCK_原始
*/
if((sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))=-1)
{
printf(“未能创建套接字:%s\n”,strerror(errno));
返回-1;
}
bzero(&clntaddr,sizeof(struct sockaddr_in));
如果(argc==6)
{
printf(“正在绑定…”\n);
clntaddr.sin_family=AF_INET;
clntaddr.sinu port=htons(atoi(argv[5]);
内部地址(argv[4],&clntaddr.sin\u addr);
如果(绑定)
(sockfd,(结构sockaddr*)和clntaddr,
sizeof(结构sockaddr_in))=-1)
{
printf(“绑定失败:%s\n”,strerror(errno));
关闭(sockfd);
返回-1;
}
}
/*
*填写服务器详细信息
*/
bzero(&servaddr,sizeof(struct sockaddr_in));
servaddr.sin_family=AF_INET;
servaddr.sinu port=htons(atoi(argv[2]);
inet_aton(argv[1],&servaddr.sin_addr);
doConnect=atoi(argv[3]);
如果(1==doConnect)
{
printf(“正在连接……”\n);
如果(-1)==
连接(sockfd,(结构sockaddr*)和servaddr,
sizeof(结构sockaddr_in)))
{
printf(“连接失败:%s\n”,strerror(errno));
关闭(sockfd);
返回-1;
}
}
if(pthread_create(&thrid,NULL,receiver,NULL)<0)
{
printf(“未能创建线程:%s\n”,strerror(errno));
关闭(sockfd);
返回-1;
}
while((read=getline(&line,&len,stdin))!=-1)
{
如果(1==doConnect)
{
if(发送(sockfd,line,len,0)<0)
{
printf(“发送()失败:%s\n”,strerror(errno));
}
}
其他的
{
if(sendto(sockfd,line,len,0,(struct sockaddr*)和servaddr,
sizeof(结构sockaddr_in))<0)
{
printf(“发送到()失败:%s\n”,strerror(errno));
}
}
}
如果(行)
自由线;
关闭(sockfd);
printf(“套接字已关闭…\n”);
睡眠(60);
}
空虚*
接收器(无效*参数)
{
字符buff[512];
而(1)
{
memset(buff,0,sizeof(buff));
如果(1==doConnect)
{
if(recv(sockfd,buff,sizeof(buff),0)<0)
{
//printf(“recvfrom()失败:%s\n”,strerror(errno));
printf(“recv()失败\n”);
}
其他的
{
printf(“recv()返回:%s\n”,buff);
}
}
其他的
{
if(recvfrom(sockfd,buff,sizeof(buff),0,NULL,NULL)<0)
{
//printf(“recvfrom()失败:%s\n”,strerror(errno));
printf(“recvfrom()失败\n”);
}
其他的
{
printf(“recvfrom()返回:%s\n”,buff);
}
}
}
}

文件描述符是进程全局的,其引用计数是进程全局的。从我在代码中读到的内容来看,最有可能发生的情况是线程仍然位于
recv
recvfrom
中,并且内核在系统调用完成之前不会关闭文件。在对某个文件的每次系统调用完成之前,您无法关闭该文件(即使您可能会释放文件描述符插槽),这将导致非常严重的错误(过去也是如此)


在调用
close
之前,拍摄线程,您将看到您的文件描述符将以您想要的方式关闭。

如果在不同的线程中关闭它被阻止的套接字描述符,系统调用不应该完成(并返回)吗?我已经为TCP编写了类似的客户端,并看到将close()替换为shutdown()有区别。使用close()时,不会在线路上发送FIN,但是使用shutdown(fd,shuth_WR)时,即使在同一描述符上的recv()系统调用中阻塞了另一个线程,FIN也会在线路上发送。操作系统不需要中止对关闭的文件描述符的系统调用。TCP can