c - 我的简单 poll() 示例仅部分起作用

标签 c sockets networking tcp polling

该程序应该在端口 8888 上接受 telnet 连接,然后使用 poll()send()recv 从每个 telnet 客户端发送消息() 但它并不是 100% 有效。似乎某些连接总是可以向任何人发送消息,并且程序运行良好,但总是至少有一个客户端无法发送消息。所有客户端始终可以接收(轮询不注册传入数据)。

这段代码自己运行,所以如果你把它放在一个文件中并用 gcc -o app filename.c 编译它,那么你可以通过 telnet 到本地主机的 8888 端口并看到它不工作。此代码是为 Fedora 编写的,但不应包含任何非 Linux 特定内容。非常感谢任何帮助。

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

#define PORT 8888
#define MAX_CONN 10
#define SECOND 1000
#define TIMEOUT (30 * SECOND)

static int listen_socket();

int main(int argc, char **argv)
{
    struct pollfd **my_fds;                  //array of pollfd structures for poll()
    struct pollfd *curr, *new_conn;          //so I can loop through
    int num_fds;                             //count of how many are being used
    int i, j;                                //for loops
    char buff[255], buff2[255];              //for sending and recieving text
    struct sockaddr_in my_addr, their_addr;  // my address information
    socklen_t sin_size;
    int buff_sz;                             //size of data recieved

    printf("App Started\n");

    //allocate space for 10 
    my_fds = (struct pollfd**) malloc(sizeof(struct pollfd*) * MAX_CONN);

    //set all the pointers to NULL
    for (i = 0; i < MAX_CONN; i++)
        *(my_fds + i) = NULL;

    //I call listen_socket() which creates a socket to listen to
    //this is anchored into my_fds array at element 0.
    curr = (struct pollfd*) malloc (sizeof(struct pollfd));
    curr->fd = listen_socket();
    curr->events = POLLIN;
    curr->revents = 0;

    *my_fds = curr;

    printf("Listening socket fd locked always at position zero in array: %d\n", curr->fd);

    //num_fds, the count of items in the array is set to 1
    //because the listen socket is already present
    num_fds = 1;

    //This is the main loop.
    //While (true)
    //  set all struct pollfd items revents to 0
    //  call poll
    //  loop through, see if there is data to read
    //      read the data
    //          loop through all sockets (except the listen_socket()) and send the data.
    while (1)
    {

        //reset all event flag
        for (i = 1; i < num_fds; i++)
        {
            curr = *(my_fds + i);
            curr->events = POLLIN | POLLPRI;
            printf("%i: fd %i\n", i, curr->fd);
            curr->revents = 0;
            send(curr->fd, "Enter some text:\n", 18, 0);
        }

        //put all this into poll and wait for something magical to happen
        printf("calling poll (%d sockets)\n", num_fds);
        if (poll(*my_fds, num_fds, TIMEOUT) == -1)
        {
            perror("poll");
            exit(0);
        }

        printf("poll returned!\n");

        //First item is the accepting socket....check it independently of the rest!
        curr = *my_fds;
        if (curr->revents != 0)
        {
            printf("We have a new connection.\nAccept goes here...\n");

            //Accept the connection
            sin_size = sizeof their_addr;
            new_conn = (struct pollfd*) malloc(sizeof(struct pollfd));
            new_conn->fd = accept(curr->fd, (struct sockaddr *)&their_addr, &sin_size);
            new_conn->events = POLLIN;
            new_conn->revents = 0;

            printf("Connection from %s\n", inet_ntoa(their_addr.sin_addr));
            sprintf(buff, "Your %i\n", num_fds);
            send(new_conn->fd, buff, 7, 0);

            //Add it to the poll call
            *(my_fds + num_fds) = new_conn;
            num_fds++;

        }
        else
        {
            //skip first one, we know that's the accepting socket (handled above).
            for (i = 1; i < num_fds; i++)
            {
                curr = *(my_fds + i);
                if (curr->revents != 0)
                {
                    buff_sz = recv(curr->fd, &buff, 254, 0);
                    buff[buff_sz] = '\0';
                    printf("Recieved: %s", buff);

                    //send the message to everyone else
                    for (j = 1; j < num_fds; j++)
                    {
                        printf("i = %i, j = %i\n", i, j);
                        if (j != i)
                        {
                            new_conn = *(my_fds + j);
                            sprintf(buff2, "%i sent you %i: %s", i, j, buff);
                            send(new_conn->fd, buff2, strlen(buff2) + 1, 0);
                        }
                    }
                }
            }
        }
    }

    printf("App Ended\n");
}

static int listen_socket()
{
    struct sockaddr_in a;
    int s;
    int yes;

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return -1;
    }
    yes = 1;
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
            (char *) &yes, sizeof(yes)) < 0) {
        perror("setsockopt");
        close(s);
        return -1;
    }
    memset(&a, 0, sizeof(a));
    a.sin_port = htons(PORT);
    a.sin_family = AF_INET;
    if (bind(s, (struct sockaddr *) &a, sizeof(a)) < 0) {
        perror("bind");
        close(s);
        return -1;
    }
    printf("Accepting connections on port %d\n", PORT);
    listen(s, 10);
    return s;
}

最佳答案

poll 不是应该采用结构数组吗?从手册页:

   int poll(struct pollfd fds[], nfds_t nfds, int timeout);

并且您正在传递一个指向结构的指针数组:

struct pollfd **my_fds; 

我认为你需要拥有

struct pollfd *my_fds = calloc(sizeof(pollfd), MAX_CONN); 

然后您的代码就有机会工作了。

关于c - 我的简单 poll() 示例仅部分起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/448331/

相关文章:

c - 我无法打印使用 "gets"函数读取的字符串

c - 指针并置使得 int_pointer 指向字符数据,反之亦然

c - fwrite() 将未知的零

c# - Amazon EC2 上的实时 TCP/IP 套接字服务器

python - UDP广播编程

c# - 如何确定远程驱动器是否有足够的空间来使用 C# 写入文件?

c - 在c中生成随机可打印的ascii字符

java - 如何修复 java.net.SocketException : Broken pipe?

java - 多个并行 Http 请求的优点

c - 如何使用预编译的驱动模块制作WinDivert 程序?