将UDP和TCP套接字绑定到同一地址并同时处理它们是否正确?

问题描述 投票:0回答:1

我试图将 UDP 和 TCP 套接字绑定到相同的 IP 地址和端口,然后处理这两种类型的连接。我已经实现了以下代码:

主函数初始化两个套接字并使用

poll()
来监视它们:

int main(int argc, char **argv) {
    if (argc != 3) {
        return EXIT_FAILURE;
    }

    struct sockaddr_in addr = derive_sockaddr(argv[1], argv[2]);

    int server_socket = setup_server_socket(addr, SOCK_STREAM);
    int server_socket_udp = setup_server_socket(addr, SOCK_DGRAM);

    struct pollfd sockets[2] = {
        {.fd = server_socket, .events = POLLIN},
        {.fd = server_socket_udp, .events = POLLIN}
    };

    struct connection_state state = {0};
    while (true) {
        int ready = poll(sockets, sizeof(sockets) / sizeof(sockets[0]), -1);
        if (ready == -1) {
            perror("poll");
            exit(EXIT_FAILURE);
        }

        for (size_t i = 0; i < sizeof(sockets) / sizeof(sockets[0]); i++) {
            if (sockets[i].revents != POLLIN) {
                continue;
            }
            int s = sockets[i].fd;

            if (s == server_socket_udp) {
                // Handle UDP
            } else if (s == server_socket) {
                int connection = accept(server_socket, NULL, NULL);
                if (connection == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
                    close(server_socket);
                    perror("accept");
                    exit(EXIT_FAILURE);
                } else {
                    connection_setup(&state, connection);
                    sockets[0].events = 0;
                    sockets[1].fd = connection;
                    sockets[1].events = POLLIN;
                }
            } else {
                assert(s == state.sock);
                bool cont = handle_connection(&state);
                if (!cont) {
                    sockets[0].events = POLLIN;
                    sockets[1].fd = -1;
                    sockets[1].events = 0;
                }
            }
        }
    }

    return EXIT_SUCCESS;
}

这是用于设置套接字的辅助函数:

static int setup_server_socket(struct sockaddr_in addr, int type) {
    const int enable = 1;
    const int backlog = 1;

    int sock = socket(AF_INET, type, 0);
    if (sock == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
        perror("fcntl");
        exit(EXIT_FAILURE);
    }

    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    if (type == SOCK_DGRAM) {
        int broadcast = 1;
        if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) == -1) {
            perror("setsockopt(SO_BROADCAST)");
            close(sock);
            exit(EXIT_FAILURE);
        }
    }

    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind");
        close(sock);
        exit(EXIT_FAILURE);
    } else {
        fprintf(stderr, "UDP or TCP socket bound to %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    }

    if (type == SOCK_STREAM) {
        if (listen(sock, backlog)) {
            perror("listen");
            exit(EXIT_FAILURE);
        }
    }

    return sock;
}

所有其他功能都可以正常工作,只是我不确定的逻辑:

将 UDP 和 TCP 套接字绑定到相同的地址和端口是否正确且安全?

poll() 逻辑是否正确处理这些套接字?具体来说,我可以依靠 poll() 来监视和区分 TCP 连接、UDP 套接字和传入数据吗?

在处理 UDP 套接字、接受 TCP 连接和处理 TCP 客户端连接之间切换时,代码中是否存在潜在问题或竞争条件?

任何见解或建议将不胜感激!

c sockets network-programming tcp udp
1个回答
0
投票

UDP 端口集与 TCP 端口集完全分开。

因此,一个套接字打开 TCP 端口 n,另一个套接字打开 UDP 端口 n 是没有问题的。

© www.soinside.com 2019 - 2024. All rights reserved.