为多线程 UDP 客户端执行“close ()”时套接字描述符未释放

2024-05-03

我在下面编写了 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 or recvfrom并且在系统调用完成之前内核不会关闭该文件。在该文件上的每个系统调用完成之前,您无法关闭文件(即使您可能会释放文件描述符槽),这会导致真正令人讨厌的错误(过去确实如此)。

在调用之前射击线程close您将看到文件描述符将按照您想要的方式关闭。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为多线程 UDP 客户端执行“close ()”时套接字描述符未释放 的相关文章

随机推荐

  • 如何为RenderTargetBitmap的输出设置透明度颜色?

    我正在尝试使用 RenderTargetBitmap 将具有透明背景的 Visual 对象保存到位图 public static RenderTargetBitmap RenderToBitmap this Visual Source in
  • LINQ TO ENTITY 无法与枚举类型进行比较

    下面是枚举叶子 public enum Leaves Annual 0 Medical 1 Hospitalization 2 Unpaid 3 下面是linq查询 public ActionResult ApproveLeave int
  • 在 Go 中获取机器 epsilon 的最简单方法

    在 Go 中获取机器 epsilon 的最简单方法是什么 浮点数的其他方面 例如精度 最小指数 最大指数 摆动等 又如何呢 我意识到有一个 math const 包 其中包含不同浮点类型的最大值和最小值 http golang org sr
  • 我应该如何使用 Perl URI 类?

    我需要在 Perl 程序中处理一些 HTTP URL 但我怀疑应该如何处理URI https metacpan org module URI类帮助我 特别是 我想使用URI用于解析相对 URL 并获取其组件的类 然而 问题是 我需要一个可以
  • Wordpress Cron 错误“SSL 证书:无法获取本地颁发者证书”

    我在安装 WordPress 时遇到错误 wp cron php 无法由 WordPress 执行 调试工具 Crontrol 报告错误 SSL证书 无法获取本地颁发者证书 WGET 无法访问 wp cron php 很可能是由于 SSL
  • 这段php代码安全吗?

    我知道我应该使用准备好的语句 但我的下一个项目将使用准备好的语句 我只需要完成这个简单的小应用程序 所以我的问题是 以下代码片段安全吗 我使用了 htmlentities 以及 mysql real escape string 因为我认为这
  • 如何更改鼠标进入/鼠标退出时按钮的图标图像?

    我想更改鼠标输入和鼠标退出时按钮的图标图像 private void jButton1MouseEntered java awt event MouseEvent evt this jButton1 setBackground Color
  • Django url 模式 - 带正斜杠的参数

    如何为两个参数创建 url 模式 其中第一个参数包含正斜杠作为其内容的一部分 da ta1 data2 最初我有以下模式 r view P
  • jQuery:在方法上取消绑定 jQuery 2.0

    在 jQuery 1 9 中live 已被弃用 因此新方法变为 document on mouseover blahblahfunc 我无法解除 blahblahfunc 的绑定 通过 unbind mouseover mouseout c
  • 如何在PHP中使用curl GET发送原始数据?

    我正在开发 REST API 虽然很容易在 cURL 中为 POST 请求设置原始 JSON 数据 payload json encode array user gt data attach encoded JSON string to t
  • CKFinder 如何在选择图像(文件:选择)时获取尺寸 URL 和尺寸(宽度/高度)?

    我正在使用 CkFinder 3 成功上传图像后 我需要能够在用户单击 选择 按钮后进行检测 文件名 ID url 原始图像的宽度和高度 目前我正在使用files choose但我找不到有关 cb 事件的信息 知道如何解决吗 代码示例将不胜
  • TSConfig JSX:React JSX 与 React

    在将 Typescript 与 React 一起使用时 我们必须指定jsx in compilerOptions in tsconfig json file It has preserve react react native react
  • go:找到模块但不包含包

    我正在尝试安装 go 的网络包 但收到 不包含包错误 终端截图 我咨询过 go 模块 latest 已找到但不包含包 https stackoverflow com questions 62974985 go module latest f
  • 使用 Pandas 滚动差异

    您好 我正在尝试使用 Pandas 滚动函数来计算下表中的滚动差异 我正在尝试生成 每月可用项目 列中的值 但没有得到任何结果 请帮忙 Item Adds Subtracts Month Monthly Available items A
  • 在opencv中保存帧而不压缩

    我正在尝试使用写 OpenCV 函数 我想保存帧 TIFF扩大 我遇到的问题是保存的图像被压缩 所以我无法使用它们 知道如何摆脱这种压缩吗 提前致谢 不要介意西奇说的话 TIFF 标志通过 LZW 压缩硬编码在 opencv 二进制文件中
  • 如何分发仅二进制的 go 包

    我想以二进制形式分发包而不包含源代码 我的演示项目目录结构是这样的 demo greet greet go hi hi go hello hello go main go main go package main import fmt de
  • 在提交 Google 表单时找不到具有给定 ID 的项目

    我创建了一个在 Google 表单上运行 onSubmit 的脚本 它应该获取上传到表单的图像的 ID 获取 Blob 形式的图像 然后将其转发到某个电子邮件地址 问题是 有时 大约十分之一 脚本会给出以下错误 例外 找不到具有给定 ID
  • 获取 WSA 错误代码的格式化消息

    我在 win32 C 应用程序中使用winsock2 我将使用 MessageBox 显示可以通过调用 WSAGetLastError 检索的网络错误 我怎样才能做到这一点 我看到 FormatMessage 但我不明白如何使用它 例如 以
  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • 为多线程 UDP 客户端执行“close ()”时套接字描述符未释放

    我在下面编写了 UDP 客户端 它基本上生成一个单独的线程来接收数据报 但是数据报仅在主线程中发送 现在 在 Linux 发行版上实例化 udpClient 1 UDP 客户端后按 ctrl D 实现退出循环 围绕 getline 调用 并