C 我的uvlib默认循环意外退出-为什么?
我正在开发一个程序,监视UDP端口的“发现”数据包。当它收到数据包时,它会将数据包回显给发送方,然后应该等待发送方发出进一步的命令 这是使用uvlib实现的(基于uvlib文档,示例:)。我初始化一个接收套接字(等待发现数据包)和一个广播套接字(用于回复发现)。当UDP数据进入时,将触发on_UDP_读取回调。在这个回调中,我获取调用方的IP和端口,并发送回显数据包 所有这些工作正常(发送系统接收回显数据包);问题是主循环(uv_run(loop,uv_run_DEFAULT))应该在回复后继续运行……但是,它以零返回码退出。我不能简单地在(kludge)循环中再次启动它,因为发送系统每次都会选择一个新端口(标准UDP行为),所以我不能(稍后)发送我要发送的批量数据 问题:为什么主循环会停止,就像我发出了uv\u stop命令一样 我想知道我的内存使用是否有问题。发送缓冲区是在函数中分配的,如:const uv_buf_t a[](可能这必须使用malloc完成) 节目如下:C 我的uvlib默认循环意外退出-为什么?,c,sockets,udp,C,Sockets,Udp,我正在开发一个程序,监视UDP端口的“发现”数据包。当它收到数据包时,它会将数据包回显给发送方,然后应该等待发送方发出进一步的命令 这是使用uvlib实现的(基于uvlib文档,示例:)。我初始化一个接收套接字(等待发现数据包)和一个广播套接字(用于回复发现)。当UDP数据进入时,将触发on_UDP_读取回调。在这个回调中,我获取调用方的IP和端口,并发送回显数据包 所有这些工作正常(发送系统接收回显数据包);问题是主循环(uv_run(loop,uv_run_DEFAULT))应该在回复后继续
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <uv.h>
#include <string.h>
#include<arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
#include <math.h>
#include <sys/socket.h>
#include <unistd.h>
#include <time.h>
#include "de_signals.h"
#define BUFFERLEN 65 // Maximum length of buffer
#define PORT 1024 // Port to watch
uv_loop_t *loop;
uv_udp_t send_socket;
uv_udp_t recv_socket;
//sem_t mutex;
//pthread_t t1;
int sockfd; // socket definition for UDP
struct sockaddr_in servaddr;
static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
//struct sockaddr_in si_DE, si_main;
void on_UDP_send(uv_udp_send_t* req, int status)
{
printf("UDP send complete, status = %d\n", status);
// the following is supposed to free the send buffer, but causes a segmentation fault
//free(req);
return;
}
void on_UDP_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) {
puts("UDP data detected");
if (nread < 0) {
fprintf(stderr, "Read error %s\n", uv_err_name(nread));
uv_close((uv_handle_t*) req, NULL);
free(buf->base);
return;
}
char sender[17] = { 0 };
uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
fprintf(stderr, "Recv from %s\n", sender);
struct sockaddr_in *sin = (struct sockaddr_in *) addr;
char ip[INET_ADDRSTRLEN];
uint16_t port;
port = htons (sin->sin_port);
printf("port = %d \n",port);
int sentBytes;
char replybuf[60];
uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
fprintf(stderr, "Recv from %s\n", sender);
for(int i=0;i<nread;i++){fprintf(stderr,"%02X ",buf->base[i]);}
fprintf(stderr,"\n");
puts("create discovery reply buf");
char b[60];
for(int i=0;i<60;i++) {b[i] = 0;}
if((buf->base[0] & 0xFF) == 0xEF && (buf->base[1] & 0xFF) == 0xFE) {
fprintf(stderr,"discovery packet detected\n");
b[0] = 0xEF;
b[1] = 0xFE;
b[2] = 0x02;
}
if((buf->base[0] & 0xFF) == 0x53 && (buf->base[1] & 0xFF) == 0x3F) {
fprintf(stderr, "STATUS INQUIRY detected\n");
b[0] = 0x4F;
b[1] = 0x4B;
port = 1024; // temporary, until we have a better way
sleep(1); // let LH get socket open
}
////////////// reply ///////////////
uv_udp_send_t send_req;
puts("create discovery reply buf");
const uv_buf_t a[]={{.base = b, .len=60}};
for(int i=0;i<60;i++){fprintf(stderr,"%02X ",a[0].base[i]);};
fprintf(stderr,"\n");
puts("ready to send");
// Here we reply to sender, using sender's IP and port
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
struct hostent* hptr = gethostbyname(sender);
if(!hptr) puts ("gethostbyname error");
servaddr.sin_addr.s_addr = //INADDR_ANY;
((struct in_addr*) hptr->h_addr_list[0])->s_addr;
uv_udp_send(&send_req, &send_socket, a, 1, (const struct sockaddr *)&servaddr,
on_UDP_send);
puts("reply issued");
// free(buf->base);
uv_udp_recv_stop(req); // ???
puts("returning from processing UDP packet");
return;
}
/////////////////////////////////////////////////////////////////////////////////
int main() {
int retcode;
//while(1==1) // this is a kludgy extra loop until we find out why uv_run halts.
//{
puts("starting");
loop = uv_default_loop();
uv_udp_init(loop, &recv_socket);
struct sockaddr_in recv_addr;
uv_ip4_addr("0.0.0.0", 1024, &recv_addr);
uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR);
uv_udp_recv_start(&recv_socket, alloc_buffer, on_UDP_read);
uv_udp_init(loop, &send_socket);
struct sockaddr_in broadcast_addr;
uv_ip4_addr("0.0.0.0", 0, &broadcast_addr);
uv_udp_bind(&send_socket, (const struct sockaddr *)&broadcast_addr, 0);
uv_udp_set_broadcast(&send_socket, 1); puts("wait for UDP handshake\n");
// Creating socket file descriptor for UDP
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
puts("start main loop");
retcode = uv_run(loop, UV_RUN_DEFAULT);
fprintf(stderr,"Return code from uv_run loop = %d \n",retcode);
//}
puts("out of main loop");
return retcode;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括“de_signals.h”
#定义缓冲区65//缓冲区的最大长度
#定义端口1024//要监视的端口
uv_环_t*环;
uv_udp_t发送_套接字;
uv_udp_t recv_插座;
//sem_t互斥体;
//pthread_t t1;
int sockfd;//UDP的套接字定义
servaddr中的结构sockaddr_;
静态无效分配缓冲区(uv\u句柄\u t*句柄、大小\u t建议大小、uv\u buf\u t*buf){
buf->base=malloc(建议的尺寸);
buf->len=建议的尺寸;
}
//si_DE、si_main中的结构sockaddr_;
发送时无效(uv\U UDP\U发送请求,int状态)
{
printf(“UDP发送完成,状态=%d\n”,状态);
//以下操作应该释放发送缓冲区,但会导致分段错误
//免费(req);
返回;
}
读取时无效(uv_UDP_t*req、ssize_t nread、常量uv_buf_t*buf、常量结构sockaddr*addr、未签名标志){
puts(“检测到UDP数据”);
如果(nread<0){
fprintf(标准,“读取错误%s\n”,uv_err_name(nread));
uv_关闭((uv_句柄*)请求,NULL);
自由(buf->base);
返回;
}
字符发送器[17]={0};
uv_ip4_名称((const struct sockaddr_in*)地址,发送方,16);
fprintf(标准,“从%s接收”,发送方);
结构sockaddr_in*sin=(结构sockaddr_in*)addr;
字符ip[INET_ADDRSTRLEN];
uint16_t端口;
端口=htons(sin->sin\u端口);
printf(“端口=%d\n”,端口);
整数字节;
char-replybuf[60];
uv_ip4_名称((const struct sockaddr_in*)地址,发送方,16);
fprintf(标准,“从%s接收”,发送方);
对于(inti=0;ibase[i]);}
fprintf(标准格式,“\n”);
puts(“创建发现回复buf”);
charb[60];
对于(inti=0;ibase[0]&0xFF)==0xEF&&(buf->base[1]&0xFF)==0xFE){
fprintf(stderr,“检测到的发现数据包”);
b[0]=0xEF;
b[1]=0xFE;
b[2]=0x02;
}
如果((buf->base[0]&0xFF)==0x53&&(buf->base[1]&0xFF)==0x3F){
fprintf(stderr,“检测到状态查询”);
b[0]=0x4F;
b[1]=0x4B;
port=1024;//暂时,直到找到更好的方法
睡眠(1);//让LH打开插座
}
//////////////答复:///////////////
uv_udp_发送_t发送_请求;
puts(“创建发现回复buf”);
常数uv_buf_t a[]={{.base=b,.len=60};
对于(int i=0;i,我了解了其中的一部分。首先,“uvlib”不是包的名称;“libuv”是。第二,循环退出的原因是因为在on_读取回调例程的末尾有一条uv_udp_recv_stop(req)指令。当没有更多工作要做时,libuv退出
剩下的问题:如果删除uv_udp_recv_stop(req)指令时考虑到这可能会使循环继续运行(它应该这样做),那么程序会因分段错误而崩溃。我向libuv团队报告了这一点(使用Github问题报告),它们也没有什么帮助,因为它们对发布在github的libuv存储库中的示例程序的正确性不承担任何责任,与UDP多播相关的测试都失败了。这对我来说意味着libuv包确实在UDP区域有一些bug;我报告了这一点,但我猜libuv团队还有更大的问题要做