如何知道客户端是否已在套接字中终止

2023-12-24

假设,写完这段代码后我有一个已连接的套接字。

if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
    perror("accept failed\n");
    exit(1);
}

我如何在服务器端知道客户端已经退出。

我的整个程序实际上执行以下操作..

  • 接受来自客户端的连接
  • 启动一个新线程,从该特定客户端读取消息,然后将此消息广播到所有连接的客户端。

如果您想查看整个代码...在整个代码中。我还在努力解决另一个问题,每当我用 Ctrl+C 杀死客户端时,我的服务器就会突然终止..这会很好如果有人可以建议问题是什么..

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>

/*CONSTANTS*/
#define DEFAULT_PORT 10000 
#define LISTEN_QUEUE_LIMIT 6
#define TOTAL_CLIENTS 10
#define CHAR_BUFFER 256

/*GLOBAL VARIABLE*/
int current_client = 0;
int connected_clients[TOTAL_CLIENTS];
extern int errno;

void *client_handler(void * socket_d);

int main(int argc, char *argv[])
{
    struct sockaddr_in server_addr;/* structure to hold server's address*/
    int    socket_d;             /* listening socket descriptor       */
    int    port;           /* protocol port number              */
    int    option_value;   /* needed for setsockopt             */
    pthread_t tid[TOTAL_CLIENTS];
    port = (argc > 1)?atoi(argv[1]):DEFAULT_PORT;

    /* Socket Server address structure */
    memset((char *)&server_addr, 0, sizeof(server_addr)); 
    server_addr.sin_family = AF_INET;               /* set family to Internet */
    server_addr.sin_addr.s_addr = INADDR_ANY;       /* set the local IP address */
    server_addr.sin_port = htons((u_short)port);    /* Set port */

    /* Create socket */
    if ( (socket_d = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        fprintf(stderr, "socket creation failed\n");
        exit(1);
    }

    /* Make listening socket's port reusable */
    if (setsockopt(socket_d, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value, 
                sizeof(option_value)) < 0) {
        fprintf(stderr, "setsockopt failure\n");
        exit(1);
    }

    /* Bind a local address to the socket */
    if (bind(socket_d, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        fprintf(stderr, "bind failed\n");
        exit(1);
    }

    /* Specify size of request queue */
    if (listen(socket_d, LISTEN_QUEUE_LIMIT) < 0) {
        fprintf(stderr, "listen failed\n");
        exit(1);
    }

    memset(connected_clients,0,sizeof(int)*TOTAL_CLIENTS);

    for (;;)
    {
        struct sockaddr_in client_addr;    /* structure to hold client's address*/
        int    alen = sizeof(client_addr); /* length of address                 */
        int    sd;                /* connected socket descriptor */

        if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
        {
            perror("accept failed\n");
            exit(1);
        }
        else printf("\n I got a connection from (%s , %d)\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));

        if (pthread_create(&tid[current_client],NULL,(void *)client_handler,(void *)sd) != 0)
        {
            perror("pthread_create error");
            continue;
        }
        connected_clients[current_client]=sd;
        current_client++; /*Incrementing Client number*/
    }

    return 0;
}

void *client_handler(void *connected_socket)
{
    int sd;
    sd = (int)connected_socket;
    for ( ; ; ) 
    {
        ssize_t n;
        char buffer[CHAR_BUFFER];
        for ( ; ; )
        {
            if (n = read(sd, buffer, sizeof(char)*CHAR_BUFFER) == -1)
            {
                perror("Error reading from client");
                pthread_exit(1);
            }
            int i=0;
            for (i=0;i<current_client;i++)
            {
                if (write(connected_clients[i],buffer,sizeof(char)*CHAR_BUFFER) == -1)
                    perror("Error sending messages to a client while multicasting");
            }
        }
    }
}

我的客户端是这样的(在回答我的问题时可能不相关)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <string.h>
#include <stdlib.h>

void error(char *msg)
{
    perror(msg);
    exit(0);
}

void *listen_for_message(void * fd)
{
    int sockfd = (int)fd;
    int n;
    char buffer[256];
    bzero(buffer,256);
    printf("YOUR MESSAGE: ");
    fflush(stdout);
    while (1)
    {
        n = read(sockfd,buffer,256);
        if (n < 0) 
            error("ERROR reading from socket");
        if (n == 0) pthread_exit(1);
        printf("\nMESSAGE BROADCAST: %sYOUR MESSAGE: ",buffer);
        fflush(stdout);
    }
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    pthread_t read_message;
    char buffer[256];
    if (argc < 3) {
        fprintf(stderr,"usage %s hostname port\n", argv[0]);
        exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
            (char *)&serv_addr.sin_addr.s_addr,
            server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");
    bzero(buffer,256);
    if (pthread_create(&read_message,NULL,(void *)listen_for_message,(void *)sockfd) !=0 )
    {
        perror("error creating thread");
    }
    while (1)
    {
        fgets(buffer,255,stdin);
        n = write(sockfd,buffer,256);
        if (n < 0) 
            error("ERROR writing to socket");
        bzero(buffer,256);
    }
    return 0;
}

接受连接后,您的recv()在特殊情况下,套接字上的内容将返回 0 或 -1。

摘自recv(3) 手册页 http://linux.die.net/man/3/recv:

成功完成后,recv() 应返回消息的长度 以字节为单位。如果没有可用消息 被接收并且对等方已 执行有序关闭,recv() 应返回 0。否则,应返回 -1 返回并设置 errno 来指示 错误。

所以,如果你的客户端优雅地退出,你会得到 0recv()在某一点。如果连接因某种原因丢失,您也可能会得到 -1,并且检查适当的 errno 会告诉您连接是否因发生其他错误而丢失。查看更多详细信息recv(3) 手册页 http://linux.die.net/man/3/recv.

Edit:

我看到你正在使用read()。尽管如此,规则与recv() apply.

当您尝试执行以下操作时,您的服务器也可能会失败write()给您的客户。如果您的客户端断开连接write()将返回 -1 并且 errno 可能会设置为EPIPE. Also, SIGPIPE如果您不阻止/忽略该信号,信号将发送给您的进程并杀死他。正如我所见,您并不这样做,这就是为什么当客户端按下 Ctrl-C 时您的服务器终止的原因。 Ctrl-C 终止客户端,因此关闭客户端套接字并使服务器的write() fail.

请参阅 mark4o 的答案,了解其他可能出错的地方的详细解释。

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

如何知道客户端是否已在套接字中终止 的相关文章

  • ASP.NET MVC 中的经典 ASP (C#)

    我有一个应用程序想要 最终 转换为 ASP NET MVC 我想要进行全面的服务升级 到 ASP NET 但想要使用当前的 ASP 内容来运行当前的功能 这样我就可以在对新框架进行增量升级的同时升级小部分 该站点严重依赖于不太成熟的 VB6
  • 使用具有现有访问令牌的 Google API .NET 客户端

    用例如下 移动应用程序正在通过 Google 对用户进行身份验证 并且在某些时候 我们需要将用户的视频发布到他的 YouTube 帐户 出于实际原因 实际发布应该由后端完成 已经存储在那里的大文件 由于用户已经通过应用程序的身份验证 因此应
  • 为什么我不能用 `= delete;` 声明纯虚函数?

    Intro 纯虚函数使用通用语法声明 virtual f 0 然而 自 c 11 以来 有一种方法可以显式地传达non existence 特殊 成员函数的 Mystruct delete eg default constructor Q
  • 向 ExpandoObject 添加方法时,“关键字 'this' 在静态属性、静态方法或静态字段初始值设定项中无效”

    我尝试向 ExpandoObject 添加一个动态方法 该方法将返回属性 动态添加 给它 但它总是给我错误 我在这里做错了什么吗 using System using System Collections Generic using Sys
  • 如何创建可以像 UserControl 一样编辑的 TabPage 子类?

    我想创建一个包含一些控件的 TabPage 子类 并且我想通过设计器来控制这些控件的布局和属性 但是 如果我在设计器中打开子类 我将无法像在 UserControl 上那样定位它们 我不想创建一个带有 UserControl 实例的 Tab
  • 从 MVC 迁移到 ASP.NET Core 3.1 中的端点路由时,具有角色的 AuthorizeAttribute 不起作用

    我正在尝试将我的项目从 UseMVC asp net core 2 2 兼容样式 升级到 UseEndpoint Routing 并且我的所有请求都被重定向到我的验证失败页面 它与声明有关 如果我删除 Authorize Roles Adm
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 如何使用recv()检测客户端是否仍然连接(并且没有挂起)?

    我写了一个多客户端服务器程序C on SuSE Linux 企业服务器 12 3 x86 64 我为每个客户端使用一个线程来接收数据 我的问题是 我使用一个终端来运行服务器 并使用其他几个终端来运行服务器telnet到我的服务器 作为客户端
  • POCO HTTPSClientSession 发送请求时遇到问题 - 证书验证失败

    我正在尝试使用 POCO 库编写一个向服务器发出 HTTPS 请求的程序 出于测试目的 我正在连接到具有自签名证书的服务器 并且我希望允许客户端进行连接 为了允许这种情况发生 我尝试安装InvalidCertificateHandler这是
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • ASP MVC:服务应该返回 IQueryable 的吗?

    你怎么认为 你的 DAO 应该返回一个 IQueryable 以便在你的控制器中使用它吗 不 您的控制器根本不应该处理任何复杂的逻辑 保持苗条身材 模型 而不是 DAO 应该将控制器返回给视图所需的所有内容 我认为在控制器类中看到查询 甚至
  • IronPython:没有名为 json 的模块

    我安装了 IronPython 我的 python 文件如下所示 import sys print sys version import json 运行它的代码 var p Python CreateEngine var scope p C
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • 如何重置捕获像素的值

    我正在尝试创建一个 C 函数 该函数返回屏幕截图位图中每四个像素的 R G 和 B 值 这是我的代码的一部分 for int ix 4 ix lt 1366 ix ix 4 x x 4 for int iy 3 iy lt 768 iy i
  • 当“int”处于最大值并使用 postfix ++ 进行测试时,代码定义良好吗?

    示例 未定义行为的一个示例是整数溢出的行为 C11dr 3 4 3 3 int溢出是未定义的行为 但这是否适用于存在循环的以下内容 并且不使用现在超出范围的副作用i 特别是 这是否后缀增量规格帮助 结果的值计算在副作用之前排序 更新操作数的
  • 耐用功能是否适合大量活动?

    我有一个场景 需要计算 500k 活动 都是小算盘 由于限制 我只能同时计算 30 个 想象一下下面的简单示例 FunctionName Crawl public static async Task
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • WinRT 定时注销

    我正在开发一个 WinRT 应用程序 要求之一是应用程序应具有 定时注销 功能 这意味着在任何屏幕上 如果应用程序空闲了 10 分钟 应用程序应该注销并导航回主屏幕 显然 执行此操作的强力方法是在每个页面的每个网格上连接指针按下事件 并在触
  • Googletest:如何异步运行测试?

    考虑到一个包含数千个测试的大型项目 其中一些测试需要几分钟才能完成 如果按顺序执行 整套测试需要一个多小时才能完成 通过并行执行测试可以减少测试时间 据我所知 没有办法直接从 googletest mock 做到这一点 就像 async选项

随机推荐

  • 我应该在 PHP PERFORMANCE-WISE 中使用 MySQL 的预准备语句吗?

    我了解 MySQL 中预准备语句的安全优势 无需在此讨论该主题 我想知道他们的性能方面 现在 我知道当使用准备好的语句的查询在单个 PHP 脚本中执行两次时 速度会更快 因为该查询仅解析一次 每个查询一次 客户端进行一次准备 然后使用二进制
  • “易失性”是否能保证多核系统的可移植 C 代码中的任何内容?

    看了一个之后 of https stackoverflow com questions 78172 using c pthreads do shared variables need to be volatile 问题 https stac
  • windows azure 中的子域映射

    我正在使用 VS 2010 WCF 和 Windows Azure 开发任务管理系统 这是一个简单的个性化任务管理应用程序 该应用程序允许用户组织和共享他们的任务 将没有 我的项目中的用户数 如果有人 订阅 该应用程序 那么我们需要使用子域
  • 传统日志记录与 AOP 日志记录

    我正在开始这个新项目 我们正在研究我们的日志记录 调试方法 我想向你们其他人提出这个问题 因为 private final static Logger logger LoggerFactory getLogger getClass publ
  • 绘图数字化 - 从图形图像中抓取样本值

    这并不是真正的 OCR 因为它不识别字符 但它与应用于曲线的想法相同 有人知道用于从 光栅 绘图图像检索值的图像处理库或已建立的算法吗 例如 在这张图中 我很难用眼睛读取精确的值 因为网格线之间存在这样的间隙 我可以使用直尺或其他工具 但它
  • 如何实现Linq OrderBy方法?

    我试图更多地了解 linq 例如 如果我想实现一个 Select 我会像这样实现 public static IEnumerable
  • ActionBarDrawerToggle 无法应用于 Android.support.v7.widget.Toolbar

    我不断收到错误消息 说 ActionBarDrawerToggle 无法应用于 v7 widget Toolbar 因为我查看了其他人如何修复类似问题 它们现在都是支持库文件 但由于某种原因错误并没有消失 错误说ActionBarDrawe
  • 如何防止 JList 在单元格边界之外进行选择?

    当用户单击列表中最后一个元素时 有什么方法可以阻止 JList 选择最后一个元素吗 这是有人问的问题here http objectmix com java 72850 jlist selection outside cell bounds
  • 使用通用 IHostBuilder 时访问 IServiceProvider

    我在用着IHostBuilder在 NET Core 2 1 控制台应用程序中 主要看起来像这样 public static async Task Main string args var hostBuilder new HostBuild
  • Java错误缺少返回语句

    好吧 我正在尝试编写这段代码 但我不断收到这个愚蠢的错误 我不知道我做错了什么 所以也许你们中的一位专家可以帮助我 import java util public class School Random randQuest new Rand
  • 有没有办法在单击 后重新加载页面?

    我想知道这一点 我有一个简单的 facebook 连接应用程序 只有在您登录并喜欢某个页面后才会显示某些内容 它有效 huzzah 但我想让它在您按下 喜欢 按钮后自动刷新 从而使其更加用户友好 这是一些代码
  • Wicket:如何处理长时间运行的任务

    我已经设置了一个 Wicket Hibernate Spring Web 应用程序 其中涉及收集一些数据 生成并返回一些文件 将其存储在数据库中 创建一些图像并将所有这些显示在网页上 这对于短期运行来说效果很好 但有时收集数据 涉及一些远程
  • 玩!框架 1.2.4 --- C3P0 设置以避免通信链路故障影响空闲时间

    我正在尝试自定义我的 C3P0 设置以避免本文底部显示的错误 这是在这个网址上建议的 http make it open blogspot com 2008 12 sql error 0 sqlstate 08s01 html http m
  • Vanilla Javascript 类中的“计算属性”

    The 计算属性该功能在流行的 JS 框架 React VueJS 中很常见 但是我们如何在普通 JS 中实现这个功能呢 假设给定一个User类 具有dateOfBirth属性 我们想计算它的age 有没有比下面的代码更好的方法来执行此任务
  • 在 View Pager 中的 Fragment 之间传递数据

    在视图分页器中的片段之间传递数据时需要帮助 我们尝试在片段内将数据作为包传递 在 Fragment getInstance 方法内部 尝试从其他 Fragment getArguments 获取数据 活动代码 package com nor
  • jQuery ajax 请求因跨源而被阻止

    如何通过ajax从远程url获取内容 jQuery ajax 请求因跨源而被阻止 控制台日志 跨源请求被阻止 同源策略不允许读取 远程资源位于http www dailymotion com embed video x28j5hv http
  • clang 构建 qt 的 mkspecs 是什么?

    如果我想在Windows下使用gcc构建qt 配置选项是 platform win32 g 但是当我想使用clang构建qt时 该选项是什么 clang windows 组合没有 我认为根据 linux g 和 linux clang 之间
  • Twitter Fabric - 无法解析符号

    我已经为 Android Studio 安装了 Twitter Fabric 插件 这很简单直接 但是当我从 Fabric 对话框复制并粘贴代码时 我的项目无法识别任何 Twitter 对象 例如以下行 private TwitterLog
  • Express 中间件、next 和 Promise

    有一个非常简单的带处理程序的 Express 路由器 router get users userId roles roleId function req res next const roleId req params roleId res
  • 如何知道客户端是否已在套接字中终止

    假设 写完这段代码后我有一个已连接的套接字 if sd accept socket d struct sockaddr client addr alen lt 0 perror accept failed n exit 1 我如何在服务器端