最近需要用VC设计一个数据采集系统。系统要求是这样的:多个数据采集模块通过WiFi与连接到无线路由器的主机进行通信。主机需要实时显示更新当前在线的所有数据采集模块。通过用户界面控制何时将数据从模块采集到主机。
我的思路是这样的:使用异步套接字,响应客户端连接消息,然后为每一个连接到主机的模块建立一个线程与模块进行交互。这些线程通过发送消息通知界面更新当前在线的模块状态。同时,这些线程接收用户对界面的操作消息,决定何时将数据采集过来并保存到文件。现在在线程接收界面控制的实现上有点疑问,我能想到的办法是,在子线程中使用select()函数实现对非阻塞的recv()操作,然后查询由用户操作而发送过来的控制消息。也就是用查询的方式等待接收界面控制消息和采集模块发送的消息。不知道能不能在子线程中用消息驱动的方式实现数据接收和消息接收,这样就不用查询的办法了,可以提高不少效率。我现在分比较少,请大家多原谅

解决方案 »

  1.   

    1.有窗口的程序用WSAAsyncSelect
    2.没有窗口的程序,或者像直接在子线程做消息循环用WSAEventSelect线程消息通信可以用PostThreadMessage,我的博客里有篇文章
      

  2.   

    或者直接用微软封装好的CAsyncSocket也可以.
      

  3.   

    zyq5945 先谢谢你,现在我主要对子线程用消息驱动的方式与终端模块通信这块的实现不知道怎么动手。我回头先去研究下WSAEventSelect和CAsyncSocket的使用,有不懂得再向您请教吧,等弄好了,在这40分的基础上我再看情况给你加分
      

  4.   

    还是有点一头雾水啊
    我想的流程是这样的:
    主线程->创建监听线程->有终端连接过来,创建子线程与终端模块和用户界面交互。
    现在的问题是,感觉在子线程中循环查询是否接收到消息和是否有用户操作通知消息太费资源,在连接的终端很多的时候估计效率很低。所以我想能不能实现这样的结果:有数据接收到消息或用户操作消息后触发子进程的回调函数进行消息处理。
    请大侠多指教啊,分我可以再加的
      

  5.   

    LZ是使用异步套子节吗?我的资源里有网络编程的电子书你看看那个WSAAsyncSelect就知道了
      

  6.   

    假如在UI线程中初始化一个异步套接字,注册FD_ACCEPT事件,然后在消息响应中创建子线程的话,在子线程中接收数据应该怎么写啊
      

  7.   

    WSAAsyncSelect创建异步套子节的话,有数据来就有个消息发送到UI线程,不是子线程.
    WSAEventSelect可以在子线程中处理,它是用个while循环检测是否有数据到来.
      

  8.   

        while (TRUE) {
            FD_ZERO(&fdR);   
            FD_SET(sock, &fdR);  
            switch (select(sock + 1, &fdR, NULL, NULL, &timeout)) {
            case -1:
                break;
            case 0:
                break;
            default:
                if (FD_ISSET(sock, &fdR)) {
                    SockRet = recv(sock, RecvBuf, sizeof(RecvBuf), 0);        
                    if (SOCKET_ERROR  == SockRet) {                     // 有错误发生
                        AfxMessageBox("Socket error on receive!");
                        BreakFlag = 1;
                        break;
                    } else if (0 == SockRet) {                          // 套接字已经被关闭
                        AfxMessageBox("the connection has been gracefully closed!");
                        BreakFlag = 1;
                        break;
                    }
                    if ('\0' != RecvBuf[SockRet - 1]) {
                        RecvBuf[SockRet] = '\0';
                    }
                    sprintf(MsgBuf, "RecvRet = %d , Data = %s, Cnt = %ld", SockRet, RecvBuf, Cnt);
                    ::PostMessage(hwnd, WM_RECVDATA, 0, (LPARAM)MsgBuf);    // 向UI线程发送消息
                    
                    sEcho = MsgBuf;
                    SockRet = send(sock, sEcho, sEcho.GetLength(), 0);
                    if (SOCKET_ERROR  == SockRet) {
                        AfxMessageBox("Socket error on send");
                        BreakFlag = 1;
                        break;
                    }               // if (SOCKET_ERROR  == SockRet) {
                }                   // if (FD_ISSET(sock, &fdR)) {
            }                       // switch (select(sock + 1, &fdR, NULL, NULL, &timeout)) {
            
            if (BreakFlag == 1) {
                break;              // 退出while循环
            }                       // if (BreakFlag == 1)
            
            Cnt ++;
            if (100000 == Cnt) {
                AfxMessageBox("Cnt == 100000");
                Cnt = 0;
            }
            
            MSG msg;
            if(PeekMessage(
                &msg,           // message information
                NULL,           // handle to window
                0,              // first message
                0,              // last message
                PM_REMOVE       // removal options
                )) {
                if (WM_WORKTHREADMSG == msg.message) {
                    AfxMessageBox((char*)msg.lParam);
                }               // if (WM_WORKTHREADMSG == msg.message) {
            }                   // if(PeekMessage(
        }                       // while (1) {这是我现在子线程的程序,用循环查询的方法接收数据和UI线程消息
      

  9.   

    那里边讲的WSAAsyncSelect,UI线程中注册的事件要通过UI线程中消息响应函数啊,到了子线程里不知道咋用啊
      

  10.   

    你上面贴的代码我看着是同步套字节的.
    你想在子线程中以消息方式响应那是不可能的,因为子线程没有窗口.
    只能就想你上面做的不断查询套字节是否可读可写;或者是WSAEventSelect设置网络事件和事件对象关联起来,在死循环中用WSAEnumNetworkEvents函数便可获得到底发生了什么网络事件(FD_READ/FD_ACCEPT/FD_CLOSE等等)