我在下面编写了 UDP 客户端,它基本上生成一个单独的线程来接收数据报,但是数据报仅在主线程中发送。现在,在 Linux 发行版上实例化(“./udpClient 1”)UDP 客户端后按 ctrl^D 后,实现退出循环(围绕 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);
}
}
}
}
最佳答案
文件描述符是进程全局的,它们的引用计数也是进程全局的。从我在代码中读到的最有可能发生的情况是,线程仍然位于 recv
或 recvfrom
中,并且内核不会关闭文件,直到该系统通话结束。在该文件上的每个系统调用完成之前,您无法关闭文件(即使您可能会释放文件描述符槽),这会导致非常严重的错误(过去确实如此)。
在调用close
之前启动线程,您将看到文件描述符将按照您想要的方式关闭。
关于c - 为多线程 UDP 客户端执行 'close ()' 时套接字描述符未释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14212584/