当前位置: 首页 > 知识库问答 >
问题:

如何停止监听并仅从一个用户接收数据,并在他断开连接时重新开始监听

文增
2023-03-14

我正在尝试编写一个服务器客户端程序。这个想法是服务器

  1. 在给定端口上侦听()

现在,我已经创建了服务器,通信也进行得很好,但是,我不知道当用户连接并开始监听断开连接时,如何停止监听。有人能帮我吗?

同时,我也在遵循beejs指南

谢啦

共有2个答案

子车芷阳
2023-03-14

让服务器在接受连接时拒绝来自客户端的连接的唯一方法是关闭(2)用于接受(2)连接的套接字。

内核不可能一次拒绝一个连接上的连接。内核只拒绝没有套接字监听的连接。

下面是一个服务器示例,其中接受套接字在连接之间关闭,因此如果启动第二个连接,第二个连接将出现econnrefered错误。

但是这有一个竞争条件:如果第二个连接碰巧在服务器程序处于接受(2)和关闭(2)系统调用之间时连接,第二个连接将被服务器打开(和关闭),没有错误。如果第二个连接中的客户端试图读取(2),它将从服务器收到一个eof,如果它试图向连接写入(2),它将收到一个错误。

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

#define F(_fmt) __FILE__":%d:%s: "_fmt, __LINE__, __func__
#define ERR(_ex_cod, _fmt, ...) do { \
        fprintf(stderr,              \
                F("ERROR: "_fmt),    \
                ##__VA_ARGS__);      \
        if (_ex_cod)                 \
            exit(_ex_cod);           \
    } while (0)

char *
sockaddr2str(
        struct sockaddr_in *addr,
        char *buf,
        size_t bufsz)
{
    char *ret_val = buf;
    snprintf(buf, bufsz,
            "%s:%d",
            inet_ntoa(addr->sin_addr),
            ntohs(addr->sin_port));
    return ret_val;
}

int main()
{
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(12345);

    for(;;) {
        int acc_sockfd = socket(PF_INET, SOCK_STREAM, 0);
        if (acc_sockfd < 0)
            ERR(EXIT_FAILURE,
                    "socket: %s\n", strerror(errno));

        /* this is needed in case you need to reopen it in a short time. */
        int reuse_addr = 1;
        int res = setsockopt(
                acc_sockfd,
                SOL_SOCKET, SO_REUSEADDR,
                &reuse_addr, sizeof reuse_addr);
        if (res < 0)
            ERR(EXIT_FAILURE,
                "setsockopt: %s\n", strerror(errno));

        res = bind(
                acc_sockfd,
                (struct sockaddr *) &server_addr,
                sizeof server_addr);
        if (res < 0)
            ERR(EXIT_FAILURE,
                    "bind: %s\n", strerror(errno));

        /* 0 listen(2) will make the queue size 0, so only
         * connections that enter while server is accept()ing
         * them will enter */
        res = listen(acc_sockfd, -1);
        if (res < 0)
            ERR(EXIT_FAILURE,
                    "listen: %s\n", strerror(errno));

        struct sockaddr_in client_addr;
        client_addr.sin_family = AF_INET;
        client_addr.sin_addr.s_addr = INADDR_ANY;
        client_addr.sin_port = 0;
        socklen_t client_addr_sz = sizeof client_addr;

        int conn_sockfd = accept(
                acc_sockfd,
                (struct sockaddr *)&client_addr,
                &client_addr_sz);
        if (res < 0)
            ERR(EXIT_FAILURE,
                "accept: %s\n", strerror(errno));

        close(acc_sockfd);

        char client_name[256];
        sockaddr2str(&client_addr,
                client_name, sizeof client_name);

        char buff[1024];
        printf("Connection from %s\n", client_name);

        FILE *f = fdopen(conn_sockfd, "r");
        if (!f)
            ERR(EXIT_FAILURE,
                "fdopen: %s\n", strerror(errno));
        int c;
        while((c = fgetc(f)) != EOF) {
            size_t n = snprintf(
                    buff, sizeof buff,
                    "[%02x]%s",
                    c,
                    c == '\n'
                        ? "\r\n"
                        : "");
            write(conn_sockfd, buff, n);
            if (c == '\033') break;
        }
        printf("Connection from %s ended\n", client_name);
        close(conn_sockfd);
        fclose(f);
    }
}
勾通
2023-03-14

停止监听的(唯一)方法是关闭监听套接字。这对已经接受的连接没有影响,因此它们可以继续使用。要重新开始监听,您需要打开一个新的监听套接字并绑定它。如果您想在TCP延迟期结束前重新打开端口,您可能需要套接字上的SO_REUSEADDR选项。

相反,您可以保留侦听套接字,在第一个连接完成之前不接受任何更多的连接,但这实际上不会侦听——尝试连接的任何其他客户端都会得到内核的握手(因此它会认为它已连接),而不是拒绝。

第三种可能更不符合您的要求,但更好的设计可能是在处理第一个连接时保持套接字打开并接受其他连接,然后立即用某种繁忙消息关闭这些新连接。这样,客户就可以至少了解一些正在发生的事情。

这完全取决于当客户端试图连接到繁忙的服务器时,您希望客户端看到什么。

 类似资料:
  • 我正在用C语言编写一个服务器,使用POSIX sockets api。 这是作为GUI应用程序的一部分运行的,它需要能够停止和启动服务器监听和向客户端发送数据。 服务器的主要部分基本上是这样的(我排除了很多代码,因为其中一些与这个问题无关。) 换句话说: 让套接字监听连接 为select()调用设置fds 使用stdin调用select(),所有连接客户端套接字,以及获取从GUI发送的任何数据的管

  • ap.onSocketOpen(CALLBACK) 监听 WebSocket 连接打开事件。 代码示例 <script src="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.inc.min.js"></script> <style> .output{ display:block; max-width

  • 我们创建的后门使用反向有效负载。为了处理反向有效负载,我们需要在Kali机器中打开一个端口,以便目标机器可以连接到它。当我们创建后门时将端口设置为,因此我们需要在Kali机器上打开8080端口。在此示例中,我们选择的有效负载的名称是。 现在,我们使用Metasploit框架拆分屏幕并侦听传入连接。我们使用命令来运行Metasploit,它应该生成类似于以下屏幕截图的输出: 要监听传入的连接,需要在

  • 问题内容: 我在componentdidmount中有一个ajax调用。然后在ajax promise中设置setState。 代码是这样的 当我导航到其他路线时,这会导致错误“无法在未安装的组件上设置状态”。 所以我认为我应该做的是在componentwillunmount中删除axios监听器。你会怎么做? 问题答案: 一个非常简单的解决方案是在unmount上设置一个标志,并在promise

  • 上一步中我们已经定义好了Server接口,并进行了多次重构,但是实际上那个Server是没啥毛用的东西。现在要为其添加真正有用的功能。大师说了,饭要一口一口吃,衣服要一件一件脱,那么首先来定个小目标——启动ServerSocket监听请求,不要什么多线程不要什么NIO,先完成最简单的功能。下面还是一步一步来写代码并进行重构优化代码结构。 关于Socket和ServerSocket怎么用,网上很多文

  • 问题内容: 我使用和创建一个实时Web应用程序。我将为用户提供对套接字连接的完全控制,例如手动断开连接和(重新)连接。 在客户端启动时,该功能可以正常运行,但是在使用之后,不会启动新连接。 问题答案: 现在可以使用socket.socket.reconnect() 相关:https : //github.com/LearnBoost/socket.io- client/issues/251