我正在使用多线程UDP侦听器,但遇到了绝对超出我的问题。
因此,我需要在多个端口中接收大量UDP数据包。在本地,对我来说最好的解决方案是在与我正在侦听的端口一样多的线程中调用非阻塞recvfrom(选择和轮询对于我的要求而言太慢了)。我正在使用线程池管理器,它只是在线程上调用并将任务排队。这是代码:
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_DONTWAIT, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
//cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
struct arg_struct args;
args.arg_port = port;
memcpy(args.buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(&args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
struct arg_struct_listenPort args;
args.arg_fd = *i;
args.arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(&args));
}
cout << "Listening threads created..." << endl;
return 0;
}
这在本地效果很好。但是,当我在生产环境中编译它时,某些端口监听数据包,而其他端口根本不监听!并且工作端口在每次执行中都会更改。我可以确认这不是防火墙问题。我也可以通过Wireshark清楚地看到这些数据包。我可以通过netcat在这些端口上接收数据包。 Netstat显示所有打开的端口。
我的本地环境是Ubuntu 18.04 VM,生产环境是Debian 9.8。
这是我所谓的套接字:
int lSocket(int port) {
//Crear Socket
int listening = socket(AF_INET, SOCK_DGRAM, 0);
if (listening == -1) {
cerr << "No se puede crear el socket";
exit(EXIT_FAILURE);
}
//Enlazar socket a un IP / puerto
struct sockaddr_in hint;
memset(&hint, 0, sizeof(hint));
hint.sin_family = AF_INET; //IPv4
hint.sin_port = htons(port); //Port
hint.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listening, (struct sockaddr*)&hint, sizeof(hint)) == -1) { //Enlaza las opciones definidas al socket
cerr << "No se puede enlazar IP/puerto" << endl;
exit(EXIT_FAILURE);
}
return listening;
}
任何建议都将不胜感激!
编辑:
根据建议,我尝试切换到阻止I / O,但是主要问题仍然存在。仍然没有收到所有打开的端口。
答案 0 :(得分:1)
太棒了!
@molbdnilo绝对正确:
您使用的指针指向生命周期已结束的对象(&args)。 这具有不确定的行为-似乎可以正常工作,但这是一个错误 需要一个fix'。
这是固定代码。将参数传递给线程时一定要小心!
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_WAITALL, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
arg_struct *args = new arg_struct;
args->arg_port = port;
memcpy(args->buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
arg_struct_listenPort *args = new arg_struct_listenPort;
args->arg_fd = *i;
args->arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(args));
}
cout << "Listening threads created..." << endl;
return 0;
}
此外,我将密切关注@John Bollinger和@Superlokkus的评论。
谢谢大家!