带有 poll() 的 UDP 服务器

UDP server with poll()

我正在编写 udp 服务器,它可以侦听多个端口。作为并行方法,我使用函数 poll()。所以server在argc中获取两个端口,然后尝试监听端口范围。然后打开msg.txt,这里保存了他从客户那里得到的所有信息。一个然后等待他们。但问题是使用 poll(),我的服务器只能监听一个端口。但是如果我删除这个功能,服务器会接受来自所有端口的消息。有什么问题吗?这是我的代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netdb.h>
#include <errno.h>

#include <stdio.h>
#include <string.h>

#include <fcntl.h>
#include <sys/poll.h>

int set_non_block_mode(int s)
{
    int fl = fcntl(s, F_GETFL, 0);
    return fcntl(s, F_SETFL, fl | O_NONBLOCK);
}
void s_close(int s)
{
    close(s);
}

int sock_err(const char *function, int s)
{
    int err = errno;
    fprintf(stderr, "%s: socket error: %d\n", function, err);
    return -1;
}

struct client
{
    char id[30];
    int msgs[20];
    struct cl *next;
    char send[81];
    int amount;
    int answer;
};

struct client *addnew(struct client *head)
{
    struct client *tmp = (struct client *)calloc(1, sizeof(struct client));
    memset(tmp->msgs, 0, 20);
    memset(tmp->send, '[=10=]', 81);
    memset(tmp->id, '[=10=]', 30);
    tmp->amount = 0;
    tmp->answer = 0;
    tmp->next = NULL;
    return tmp;
}

struct client *search(struct client *head, unsigned int ip, int port)
{
    char str[30];
    sprintf(str, "%u.%u.%u.%u:%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip)&0xFF, port);
    struct client *tmp = head;
    if (tmp!=NULL){
        while (1)
        {
            if (strcmp(tmp->id, str) == 0)
            {
                return tmp;
            }
            if(tmp->next==NULL)break;
            tmp = tmp->next;
        }
        tmp->next = addnew(head);
        tmp = tmp->next;
        strcpy(tmp->id, str);
        return tmp;
    } else {
        tmp = addnew(head);
        strcpy(tmp->id, str);
        return tmp;
    }
}

int parcing(FILE *text, char *buffer, int s, struct sockaddr_in *addr, struct client *head, int port)
{
    int flags = MSG_NOSIGNAL;
    int addrlen = sizeof(*addr);
    unsigned int ip = ntohl((*addr).sin_addr.s_addr);
    struct client *tmp = search(head, ip, port);
    int n;
    memcpy(&n, buffer, 4);
    n = ntohl(n);
    if (tmp->msgs[n] == 0)
    {
        tmp->msgs[n] = 1;
        tmp->answer++;
        n = htonl(n);
        memcpy(&tmp->send[4 * tmp->amount], tmp->send, 4 * tmp->amount);
        tmp->amount++;
        memcpy(tmp->send, &n, 4);
        fprintf(text, "%s %d:%d:", tmp->id, buffer[4], buffer[5]);
        memcpy(&n, &buffer[6], 2);
        n = ntohs(n);
        fprintf(text, "%hu ", n);
        memcpy(&n, &buffer[8], 2);
        n = ntohs(n);
        fprintf(text, "%hi ", n);
        for (int i = 10; i < 22; i++)
            fprintf(text, "%c", buffer[i]);
        fprintf(text, " %s\n", &buffer[22]);
        sendto(s, tmp->send, 4 * tmp->amount, flags, (struct sockaddr *)addr, addrlen);
        if (strcmp(&buffer[22], "stop") == 0)
            return 0;
        return 1;
    }
    else
    {
        sendto(s, tmp->send, 4 * tmp->amount, flags, (struct sockaddr *)addr, addrlen);
    }
}

int main(int argc, char *argv[])
{
    int i;
    int flags = MSG_NOSIGNAL;
    int start, end;
    if (argc == 3)
    {
        start = atoi(argv[1]);
        end = atoi(argv[2]);
    }
    else
    {
        start = atoi(argv[1]);
        end = start;
    }
    //start = 8035;
    //end = start;
    int AmountOfPorts = end - start + 1;
    struct pollfd *pfd = (struct pollfd *)calloc(AmountOfPorts, sizeof(struct pollfd));
    int *s = (int *)calloc(AmountOfPorts, sizeof(int));
    struct sockaddr_in *addr = (struct sockaddr_in *)calloc(AmountOfPorts, sizeof(struct sockaddr_in));
    for (int i = 0; i < AmountOfPorts; i++)
    {
        s[i] = socket(AF_INET, SOCK_DGRAM, 0);
        if (s[i] < 0)
            return sock_err("socket", s[i]);
        set_non_block_mode(s[i]);
        memset(&addr[i], 0, sizeof(addr));
        addr[i].sin_family = AF_INET;
        addr[i].sin_port = htons(start + i);
        addr[i].sin_addr.s_addr = htonl(INADDR_ANY);
        if (bind(s[i], (struct sockaddr *)&addr[i], sizeof(addr[i])) < 0)
            return sock_err("bind", s[i]);
        pfd[i].fd = s[i];
        pfd[i].events = POLLIN | POLLOUT;
    }
    int g = 1;
    struct client *head = NULL;
    struct client *tmp = NULL;
    FILE *text = fopen("msg1.txt", "w");
    char buffer[131072] = {0};
    int addrlen = 0;
    do
    {
        int ev_cnt = poll(pfd, sizeof(pfd) / sizeof(pfd[0]), 100000);
        if (ev_cnt > 0)
        {
            for (i = 0; i < AmountOfPorts; i++)
            {
                if (pfd[i].revents & POLLHUP)
                { 
                    s_close(s[i]);
                }
                if (pfd[i].revents & POLLERR)
                { 
                    s_close(s[i]);
                }
                if (pfd[i].revents & POLLIN)
                { 
                    addrlen = sizeof(addr[i]);
                    recvfrom(s[i], buffer, sizeof(buffer), 0, (struct sockaddr *)(&addr[i]), &addrlen);
                    if (rcv > 0)
                    {
                        if (!parcing(text, buffer, s[i], &addr[i], head, start + i))
                        {
                            g = 0;
                            break;
                        }
                    }
                    if (pfd[i].revents & POLLOUT)
                    { 
                        addrlen = sizeof(addr[i]);
                        unsigned int ip = ntohl((*addr).sin_addr.s_addr);
                        tmp = search(head, ip, start+i);
                        sendto(s[i], tmp->send, 4 * tmp->amount, flags, (struct sockaddr *)&addr[i], addrlen);
                    }
                }
            }
        }
        else
        {
        }
    } while (g);
    fclose(text);
    for (int i = 0; i < AmountOfPorts; i++)
        s_close(s[i]);
    return 0;
}

您将 pfd 声明为指向 struct pollfd 的指针:

struct pollfd *pfd;

因此,以下构造将无法按预期工作(要使其工作,pfd 必须是一个数组:struct pollfd pfd[N]):

sizeof(pfd) / sizeof(pfd[0]) //in call to poll

上面的表达式可以这样用数字表示(取决于你的机器和os):

//sizeof(struct pollfd*) / sizeof(struct pollfd)
8 / (4 + 2 + 2) => 8 / 8 => 1

//your expectation:
16 / 8 => 2

这意味着,poll 将只监听第一个 pollfd,因为参数 nfds 设置为 1。

注意:我没有完全检查你的代码,但是因为你经常使用指针(calloc)和sizeof,确保你没有做同样的事情其他地方出错。记住 pointer != array.