libuv 回调函数似乎无法正常不调用

天下如山 2016-04-19 09:12:00
我在qt下使用libuv库,引用其UDP相关方法,完全是安装官方的sample去写的,但是不知道为什么回调函数不能被执行,从而无法接受到数据,或者发送数据时,数据是可以被发出去,其他接受软件可以收到UDP,但是同样程序内的回调函数不能被执行,是否还有一些我没有注意到的地方?请指正,已经折腾好几天了。

代码如下:
.h
class UDPSOCKETSHARED_EXPORT UDPSendSocket : public QObject
{
Q_OBJECT
public:
explicit UDPSendSocket(QObject *parent = 0);
~UDPSendSocket();
// 序列化一些参数
void init(QString addr,int port,int type = 0);
// 发送buf
void SendBuf(const QByteArray & ba);

signals:

public slots:
private:
uv_loop_t *m_uv_loop; //libuv注册
uv_udp_t m_uv_send; //
uv_udp_send_t m_send_req;
struct sockaddr_in bind_addr; // libuv 地址信息配置
// 发送报文的回调函数
static void cl_send_cb(uv_udp_send_t* req, int status);
};

.cpp
UDPSendSocket::UDPSendSocket(QObject *parent) : QObject(parent),m_uv_loop(0)
{
uv_ip4_addr("0.0.0.0", 0, &bind_addr); // 初始化

}

UDPSendSocket::~UDPSendSocket()
{

}

/**
* @brief UDPSendSocket::init
* 初始化,序列化一些IP和端口号
* @param addr IP
* @param port port
* @param type 0:正常,1:组播,2:广播
*/
void UDPSendSocket::init(QString addr, int port,int type)
{
m_uv_loop = uv_default_loop();
uv_udp_init(m_uv_loop, &m_uv_send);
uv_ip4_addr("192.168.1.100", 10000, &bind_addr);
}

/**
* @brief UDPSendSocket::SendBuf
* 发送报文
* @param ba
*/
void UDPSendSocket::SendBuf(const QByteArray &ba)
{
qDebug() <<"UDPSendSocket::SendBuf" <<"#####################" <<ba.toHex();
uv_buf_t buf = uv_buf_init( const_cast<char *>( ba.data() ), ba.size());
uv_udp_send(&m_send_req, &m_uv_send,&buf, 1,
(const struct sockaddr *)&bind_addr, cl_send_cb);
// delete data;
}
void UDPSendSocket::cl_send_cb(uv_udp_send_t *req, int status)
{
qDebug()<<"UDPSendSocket::cl_send_cb" << status;
}


按照sample 按理论上说 cl_send_cb 这个回调函数应该是在发送成功,或者某个时刻被执行,但是,看起来没有。并且报文是可以发出去的

在线等。。谢谢
...全文
271 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
天下如山 2016-04-19
  • 打赏
  • 举报
回复
现在 我调查了一下,似乎是因为libuv的事件循环与Qt的事件循环发生冲突,从而导致libuv的事件循环失效。那么我应该如何避免呢? 比如说,Qt的事件循环肯定是要需要的,但是我在使用Libuv的时候,如果能够让之共存?
赵4老师 2016-04-19
  • 打赏
  • 举报
回复
我想就象下面代码的思路一样:
// OpenGL的程序框架.cpp : Defines the entry point for the application.
// 学程序编游戏系列丛书
// 唐明理 E_mail: cqtmL@163.com
//====================================================================
#include "stdafx.h"
#include "OpenGL.h"
//////////////////////////////////////////////////////////
OpenGL* m_OpenGL;
HDC     hDC;        // GDI设备句柄,将窗口连接到 GDI( 图形设备接口)
HGLRC   hRC=NULL;   // 渲染描述句柄,将OpenGL调用连接到设备描述表
HWND    hWnd=NULL;  // 保存 Windows 分配给程序的窗口句柄
int     Width = 800;// 窗口宽
int     Height= 600;// 窗口高
int     bits  = 16; // 颜色深度
void GameLoop()
{   MSG msg;
    BOOL fMessage;
    PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
    while(msg.message != WM_QUIT)   // 消息循环
    {   fMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);
        if(fMessage)                //有消息
            { TranslateMessage(&msg);
              DispatchMessage(&msg);
            }
        else  m_OpenGL->Render();   //无消息
    }
}
LRESULT WINAPI MsgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam )// 消息处理
{   switch(message)
    {   case WM_CREATE:                     // 建立窗口
            hDC = GetDC(hWnd);              // 获取当前窗口的设备句柄
            m_OpenGL->SetupPixelFormat(hDC);// 调用显示模式安装功能
            return 0;       break;
        case WM_CLOSE:                      // 关闭窗口
            m_OpenGL->CleanUp();            // 结束处理
            PostQuitMessage(0);
            return 0;       break;
        case WM_SIZE:                       // 窗口尺寸变化
            Height = HIWORD(lParam);        // 窗口的高
            Width  = LOWORD(lParam);        // 窗口的宽
            if (Height==0)  Height=1;       // 防止被0 除
            m_OpenGL->init(Width,Height);
            return 0;       break;
        case WM_DESTROY:                    // 退出消息
            PostQuitMessage(0);
            return 0;       break;
        case WM_KEYUP:                      // 按ESC退出,全屏模式必需要加入的退出方式。
            switch (wParam)
            { case VK_ESCAPE:
                    m_OpenGL->CleanUp();    // 结束处理
                    PostQuitMessage(0);
                    return 0;break;
            }
        default:            break;
    }
    return (DefWindowProc(hWnd, message, wParam, lParam));
}
INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,INT )// WinMain程序入口
{   // 注册窗口类
    bool fullScreen =TRUE;
    DWORD   dwExStyle;      // Window 扩展风格
    DWORD   dwStyle;        // Window 窗口风格
    RECT    windowRect;     // 窗口尺寸
    int     nX=0,nY=0;
    dwExStyle=WS_EX_APPWINDOW|WS_EX_WINDOWEDGE; // 使窗口具有3D外观
    dwStyle=WS_OVERLAPPEDWINDOW;                // 使用标准窗口
    //WS_OVERLAPPEDWINDOW是有标题栏,窗口菜单,最大、小化按钮和可调整尺寸的窗口
    int wid=GetSystemMetrics(SM_CXSCREEN);      // 获取当前屏幕宽
    int hei=GetSystemMetrics(SM_CYSCREEN);      // 获取当前屏幕高
    nX=(wid-Width)/2;nY=(hei-Height)/2;         // 计算窗口居中用
//-------------------------------------------------------------------
    AdjustWindowRectEx(&windowRect,dwStyle,FALSE,dwExStyle);
                                    //根据窗口风格来调整窗口尺寸达到要求的大小
    char cc[]="tml";
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      cc, NULL };
    RegisterClassEx( &wc );
    m_OpenGL=new OpenGL();//
    hWnd = CreateWindowEx(NULL,cc,"学OpenGL编3D游戏 [ 1.OpenGL的程序框架 ])",
                          dwStyle|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
                          nX, nY,Width, Height,
                          NULL,NULL,hInst,NULL);    // 创建窗口
    ShowWindow( hWnd, SW_SHOWDEFAULT );             // 显示窗口
    UpdateWindow( hWnd );                           // 刷新窗口
    GameLoop();                                     // 进入消息循环
    return 0;
}
天下如山 2016-04-19
  • 打赏
  • 举报
回复
引用 2 楼 zhao4zhong1 的回复:
我首先想到的是多线程。
多线程我也尝试了,但是不行,因为Qt的多线程也是依赖于qt事件,这个和libuv事件有些冲突。 我想是否可以Qt中运行两套事件机制? 官方文档上有一句话“你还可以将libuv的event loop嵌入到其它基于event-loop的库中。比如,想象着一个基于Qt的UI,然后Qt的event-loop是由libuv驱动的,做着加强级的系统任务” 这个不是特别理解?
赵4老师 2016-04-19
  • 打赏
  • 举报
回复
我首先想到的是多线程。
基于事件驱动的网络框架源码 首先看一下Server类,这个类就是整个框架的核心类,在这个类中只需要 s=new Server(8883,4); s->setUserConnectionCallback(onConnect); s->setUserMessageCallBack(onMessage); s->start(); 就可以启动一个4个线程在8883端口监听的完整的网络程序,其中的两个onXXX就是网络程序需要处理的业务 Server类中包括了有一个重要的类叫做Eventlooper这个类就是对epoll的封装,要用epoll_ctl注册到epoll上的fd又被封装为Channel类,当有数据到来需要操作时,channel中的几个函数指针就指向了需要回调的函数, 这里使用了boost库的function 其中的函数定义为: typedef boost::function EventCallBack; 在epoll返回的时候Eventlooper会遍历可以操作的所有channel,并调用其成员函数handleEvent,该函数会判断events,也就是EPOLLIN EPOLLPRI等,并更具相应的需要去调用处理函数。 这里的Channel并不直接使用而是做基类存在的,更直接的操作在Acceptor和TcpConnection中,其中的 Acceptor 对应了接受连接的socketfd,而TcpConnection则封装了socket的读写操作,在Server的构造函数中会创建一个Acceptor类,真正accept成功以后又会调用到Server的OnConnection函数中,这个函数会根据每个线程的负载将客服端连接的fd注册进相应线程的epoll(当然在单线程的情况下就只有一个epoll)。最后一个作为缓冲区的类charbuff,用链表将单个7KB的缓冲区穿在一起,当数据大于7kb的时候会自动将其释放,避免内存不足,如果数据的块数多余一块那么发送数据就会调用writev。至此整个框架的流程就都已经清楚了,一个简单的实现。 在此还要感谢一下linux多线程网络服务器编程的作者陈硕,CINF的实现部分就是参考其网络框架muduo来的。

64,663

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧