带有 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.
我正在编写 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.