基于AsyncSelect模型的网络应用,直接用MFC封装好的CSocked就好了  简单健壮

解决方案 »

  1.   

    to allenhiman:
    谢谢了 我先看下!
      

  2.   

    WSAAsyncSelect是什么时候执行的?ConnSocket是什么样的SOCKET?
      

  3.   

    to cnzdgs:
    1)SOCKET ConnSocket;
    2)WSAAsyncSelect 是在单击m_TPTDlg实例上的按钮之后通过线程调用执行的
    void CTPTMPTComCfig::OnBtnStart() 
    {

    CString str="服务器:"+GetIPAddress()+"端口号:2000正在进行监听";
    m_ctlMsgList.InsertItem(i++,str);
    //ServerSocket在初始化对话框时赋值,用于监听,默认连接个数:5
    int isListenOk=listen(ServerSocket,5);//启动监听,P77
    if (0!=isListenOk)
    {
    MessageBox("侦听失败!");
    return ;
    }
    //pServerThread:启动工作线程;等待客户请求到来;调用1.1
    pServerThread=AfxBeginThread(Server,0);
    }
    UINT Server(LPVOID p)
    {      
    int len=sizeof(SOCKADDR);
    //1. 获得当前运行对话框句柄
    CTPTMPTComCfig *dlg=(CTPTMPTComCfig*)AfxGetApp()->GetMainWnd();
    CFrameWnd* SDI=(CFrameWnd*)AfxGetApp()->GetMainWnd();
    CPictureView* pView=(CPictureView*)SDI->GetActiveView();  //SOCKET tepSock=dlg->ServerSocket;
    SOCKET tepSock=ServerSocket;
    //sockCon和ConnSocket成员为具体工作(传输数据等)的套接字TCP连接的套接字
    //单独定义sockCon是为了方便错误判断和处理
    SOCKET sockCon=accept( tepSock,(SOCKADDR*)&(dlg->localaddr),&len);
    //dlg->ConnSocket=sockCon;
    ConnSocket=sockCon;
    if(sockCon==INVALID_SOCKET)
    {
    AfxMessageBox("连接失败!");
    }
    //连接成功;注册网络事件,将端口设置为非阻塞模式
    //NETWORK_EVENT为待接收的消息,在1.2中进行处理
    //FD_READ|FD_WRITE|FD_CLOSE:准备好读、写和关闭网络连接

    int socketSel=WSAAsyncSelect(ConnSocket,pView->m_hWnd,
    NETWORK_EVENT,FD_READ|FD_WRITE|FD_CLOSE);

    if(SOCKET_ERROR==socketSel)
    {
    AfxMessageBox("注册网络事件失败!");
    return 0;
    }

    return 0;
    }谢谢!
      

  4.   

    消息是在CPictureView类中响应的吗?
    你的程序搞的太复杂了,既然要用WSAAsyncSelect,就不要另创建线程了,把listen的socket也用WSAAsyncSelect注册消息来处理。另外,WSAAsyncSelect也许不能这样跨线程使用,没这样试过。
      

  5.   

    to cnzdgs: 
    1)消息也是在m_CTPTDialog 中响应的,所有的消息注册消息响应都是在在CTPTDialog 中进行处理的;
    我跟踪了下注册似乎成功了,但就是没有响应,难道是没有注册时的窗口句柄有问题?到底是用哪个句柄呢?
      

  6.   

    WSAAsyncSelect中指定的窗口句柄是pView->m_hWnd,所以要在CPictureView类中响应;如果要在对话框类中响应,要指定对话框的窗口句柄。
      

  7.   

    //定义用户消息
    #define NETWORK_EVENT WM_USER+166//定义网络事件
    #define WM_PAUSE WM_USER+177 //定义暂停消息
    #define WM_STOP WM_USER+178// 定义暂停消息
    #define WM_CONTINUE WM_USER+179//定义继续消息
    #define WM_SYN WM_USER+180 //定义同步消息
    #define WM_MONITOR WM_USER+181 //定义监控消息
    //声明消息处理函数,响应用户消息
    afx_msg void OnNetEvent(WPARAM wParam,LPARAM lParam);
    afx_msg void OnPause(WPARAM wParam,LPARAM lParam);
    afx_msg void OnStop(WPARAM wParam,LPARAM lParam);
    afx_msg void OnContinue(WPARAM wParam,LPARAM lParam);
    afx_msg void OnSyn(WPARAM wParam,LPARAM lParam);
    afx_msg void OnMonitor(WPARAM wParam,LPARAM lParam);void CTPTMPTComCfig::OnNetEvent(WPARAM wParam,LPARAM lParam)
    {
           ...
    case FD_READ:

    AfxBeginThread(RecvProc,0);//启动接收进程,调用1.3
    break;
    }
           ...
    }UINT RecvProc(LPVOID lpvoid)
    {
    char buf[1029];//定义接收缓存
    CString str;//中间变量
    int k;
    CTPTMPTComCfig* pdlg=(CTPTMPTComCfig*)AfxGetApp()->GetMainWnd();
    int n=recv(CurSock,buf,1028,0);//CurSock:已经建立TCP通信的套接字
    if (SOCKET_ERROR==n)
    {
    AfxMessageBox("连接未正常关闭!");
    } buf[n]='\0';
    //1. 判断是否为测试例数据
    if((strchr(buf,'-')!=NULL))
    {   
    str=buf;
    pdlg->m_testcase[pdlg->count]=buf;//将测试例保存下来
    pdlg->count++;//移动测试例计数

    pdlg->m_ctlMsgList.InsertItem(pdlg->i++,buf);//显示所保存的测试例的名称

    k=pdlg->FindNumber();//查找IP地址在列表中对应的序号(从零起),调用1.4

    str="TPT"+TPTInfo[k].num+":"+"测试例"+str+"已经收到!";
    //if( send(pdlg->CurSock,str,str.GetLength(),0)==SOCKET_ERROR)//通知客户端
    if( send(CurSock,str,str.GetLength(),0)==SOCKET_ERROR)//通知客户端
    {
    AfxMessageBox("发送数据错误!");
    }
    }

    //2. 判断是否为控制命令
    else if( strcmp(buf,"START")==0)//1. 响应客户端'开始测试'消息,调用'开始测试'线程
    {
    m_pStartThread=AfxBeginThread(StartTest,0);//调用1.6,启动“开始测试”工作线程
    }
    else if(strcmp(buf,"PAUSE")==0)//2. 暂停,响应客户端'暂停测试'消息,通过消息机制
    {
    ::PostMessage(pdlg->m_hWnd,WM_PAUSE,0,0);//调用1.7
    }
    else if(strcmp(buf,"STOP")==0)//3. 停止,响应客户端'停止测试'消息,通过消息机制
    {
    ::PostMessage(pdlg->m_hWnd,WM_STOP,0,0);//调用1.8
    }
    else if(strcmp(buf,"CONTINUE")==0)//4. 继续,响应客户端'继续执行测试'消息
    {
    ::PostMessage(pdlg->m_hWnd,WM_CONTINUE,0,0);//调用1.9
    }
    else if(strcmp(buf,"SYN")==0)//5. 同步,响应客户端'同步测试'命令,并在本地进行处理(消息响应)
    {
    ::PostMessage(pdlg->m_hWnd,WM_SYN,0,0);//调用1.10
    }

    else if(strcmp(buf,"MONITOR")==0)//6. 监控,响应客户端'监控测试'命令,并在本地进行处理(消息响应)
    {
    ::PostMessage(pdlg->m_hWnd,WM_MONITOR,0,0);//调用1.11
    }
    else  pdlg->m_ctlMsgList.InsertItem(pdlg->i++,buf);//7. 其他

    return 0;
    }说明:
    1)这些函数全在CTPTMPTComCfig类文件中
    2)CTPTMPTComCfig是由CDialog继承而来的!
      

  8.   

    UINT Server(LPVOID p)
    {      
    int len=sizeof(SOCKADDR);
    //1. 获得当前运行对话框句柄
    CTPTMPTComCfig *dlg=(CTPTMPTComCfig*)AfxGetApp()->GetMainWnd();
            SOCKET tepSock=ServerSocket;
    //sockCon和ConnSocket成员为具体工作(传输数据等)的套接字TCP连接的套接字
    //单独定义sockCon是为了方便错误判断和处理
    SOCKET sockCon=accept( tepSock,(SOCKADDR*)&(dlg->localaddr),&len);
    //dlg->ConnSocket=sockCon;
    ConnSocket=sockCon;
    if(sockCon==INVALID_SOCKET)
    {
    AfxMessageBox("连接失败!");
    }
    //连接成功;注册网络事件,将端口设置为非阻塞模式
    //NETWORK_EVENT为待接收的消息,在1.2中进行处理
    //FD_READ|FD_WRITE|FD_CLOSE:准备好读、写和关闭网络连接

    int socketSel=WSAAsyncSelect(ConnSocket,dlg->m_hWnd,
    NETWORK_EVENT,FD_READ|FD_WRITE|FD_CLOSE);

    if(SOCKET_ERROR==socketSel)
    {
    AfxMessageBox("注册网络事件失败!");
    return 0;
    }

    return 0;
    }中的:
    ......
    CTPTMPTComCfig *dlg=(CTPTMPTComCfig*)AfxGetApp()->GetMainWnd();
    ......
    int socketSel=WSAAsyncSelect(ConnSocket,dlg->m_hWnd,
    NETWORK_EVENT,FD_READ|FD_WRITE|FD_CLOSE);这两句是不是已经获得了Dialog的窗口句柄呢?谢谢!
    另外: 怎么给分呢?
      

  9.   

    你说的除了把“把listen的socket也用WSAAsyncSelect注册消息来处理”之外的方法:
    1)WSAAsyncSelect中指定的窗口句柄是pView->m_hWnd,所以要在CPictureView类中响应:
    ......
    CFrameWnd* SDI=(CFrameWnd*)AfxGetApp()->GetMainWnd();
    CPictureView* pView=(CPictureView*)SDI->GetActiveView(); 
    ......
    int socketSel=WSAAsyncSelect(ConnSocket,pView->m_hWnd,
    NETWORK_EVENT,FD_READ|FD_WRITE|FD_CLOSE);
    2)如果要在对话框类中响应,要指定对话框的窗口句柄:
    ......
    CTPTMPTComCfig *dlg=(CTPTMPTComCfig*)AfxGetApp()->GetMainWnd();
    ......
    int socketSel=WSAAsyncSelect(dlg->ConnSocket,dlg->m_hWnd,
    NETWORK_EVENT,FD_READ|FD_WRITE|FD_CLOSE);
    我似乎都尝试过,但还是没响应;
    另外:
    我尝试了“把listen的socket也用WSAAsyncSelect注册消息来处理”,这里注册了之后似乎accept()之后建立的通信套接字就不能注册了?
    难道两个都注册?请解释下,谢谢!
      

  10.   

    我用侦听套接字注册网络事件之后在该套接字的基础上似乎就不能accept从而产生合法的通信套接字!谢谢!
      

  11.   

    你的程序是SDI架构,AfxGetApp()->GetMainWnd()获得的是主框架类对象,不是对话框类对象,如果对话框类对象是在视图类中定义的,可以先获取视图类指针,然后再用该指针访问对话框对象。或者在创建线程的时候把对话框指针作为参数传给线程。
      

  12.   

    to cnzdgs:
    谢谢哈 我尝试着做下!再反馈情况!
      

  13.   

    to cnzdgs: 
    非常感谢,我使用this指针就可以了!谢谢了!再次感谢!