zoukankan      html  css  js  c++  java
  • 基于UDP的MFC局域网聊天程序

    开发环境VS2010

    这个小程序用到了UDP通信和多线程的知识。

    已知问题:不能显示中文。发送内容不能过长。滚动条没有自动滚到最后一行。

    基本思路:在初始化对话框的时候就创建一个线程,在这个线程里进行套接字初始化,然后一直阻塞到接受到消息。

    总结:接受消息显示采用的是往CString 变量里面追加东西,然后再分行显示。这样做个人感觉肯定不是最优,但是我目前只能想到这个办法了。至于不能显示中文的问题,我知道发生在接收消息阶段。整个消息发送接收过程是这样处理的:从控件上获取到CString的,然后转换格式成wchar_t,再格式化成char* 通过sendto函数发送过去。接受端接收了char*也是转成wchar_t再转成CString显示的。这里面格式转换是存在问题的,希望有人能指点。

    关键代码存档


    在头文件里添加成员变量static DWORD WINAPI ThreadProc1(LPVOID lpParameter); 下面和也是。

    View Code
    1 /*变量声明*/
    2 HANDLE hThread1;
    3 HANDLE hThread2;
    4 CString m_Edit;  //发送消息的编辑控件的成员变量
    5 CIPAddressCtrl m_ip;  //ip控件的成员变量
    6 CString m_msg;  // 显示消息控件的成员变量,没用到
    7 
    8 void OnOK();  /*隐藏默认的OnOK函数,就是按程序运行时下回车时调用的函数,这里我们要重新定义一下*/
    View Code
      1 /*在OnInitDialog()中添加额外的初始化代码*/
      2 hThread1 = ::CreateThread(NULL,0,ThreadProc1,this,0,NULL);  /*在初始化对话框的时候就创建线程*/
      3 
      4 
      5 /*点击发送按钮时的代码*/
      6 void CMFCUDPDlg::OnBnClickedButton1()
      7 {
      8     
      9      CSocket socket;
     10      if( !socket.Create(0, SOCK_DGRAM, NULL) )
     11      {
     12         MessageBox(_T("创建套接字失败"));
     13      }
     14      //UpdateData(TRUE);    
     15      
     16      wchar_t *sendMsg;
     17      GetDlgItemTextW(IDC_EDIT2,m_Edit);
     18      
     19      sendMsg=m_Edit.GetBuffer(m_Edit.GetLength()); 
     20      m_Edit.ReleaseBuffer();
     21 
     22      /*把char类型的sendMsg转化为wchar_t类型的WStr。
     23     size_t len = strlen(sendMsg) + 1;
     24     size_t converted = 0;
     25     wchar_t *WStr;
     26     WStr=(wchar_t*)malloc(len*sizeof(wchar_t));
     27     mbstowcs_s(&converted, WStr, len, sendMsg, _TRUNCATE);
     28     */
     29 
     30       /*测试类型转换以后是否有乱码 ,我现在觉得下面这种格式化,还是从wchar_t变成CString方便
     31     m_Edit.Format(_T("%s"),sendMsg); 
     32      AfxMessageBox(m_Edit);
     33     */
     34 
     35      //此时的sendMsg已经变成了wchar_t类型的,接下来要把它变成char*型的
     36       size_t len = wcslen(sendMsg) + 1;
     37       size_t converted = 0;
     38       char *message;
     39       message=(char*)malloc(len*sizeof(char));
     40       wcstombs_s(&converted, message, len, sendMsg, _TRUNCATE);
     41 
     42     /*获取ip空间里的ip地址*/
     43     BYTE f0, f1, f2, f3; 
     44     m_ip.GetAddress(f0, f1, f2, f3); 
     45     CString m_addr; 
     46     m_addr.Format(_T("%d%s%d%s%d%s%d"), f0, ".", f1, ".", f2, ".", f3); 
     47 
     48     int length = socket.SendTo(message, strlen(message), 9000, m_addr, 0);
     49     socket.Close();
     50     
     51 
     52 }
     53 
     54 /*因为线程函数是静态的,不能调用非静态成员,在此创建一个类类型的指针*/
     55 CMFCUDPDlg* p;
     56 /*初始化对话框时,创建线程做的事情*/
     57 DWORD WINAPI CMFCUDPDlg::ThreadProc1(LPVOID lpParameter)
     58 {
     59     
     60         CMFCUDPDlg *p=(CMFCUDPDlg*)lpParameter;
     61         CSocket Server;  
     62 
     63         // 创建用于接收数据报的套接字
     64         if (Server.Create(9000, SOCK_DGRAM, NULL)== 0) 
     65         {
     66             AfxMessageBox(_T("创建Socket失败"));
     67             return -1;
     68         }
     69 
     70     while(TRUE)
     71     {
     72             SOCKADDR_IN ClntAddr; 
     73             int clntAddrLen = sizeof(ClntAddr);
     74             char echoBuffer[1024]=""; 
     75             CString buffer;
     76             static CString save;
     77         
     78             //一直阻塞到有客户端发来数据
     79             int recvMsgSize = Server.ReceiveFrom(echoBuffer,sizeof(echoBuffer), (SOCKADDR*)&ClntAddr, &clntAddrLen, 0);
     80             
     81             if (recvMsgSize < 0)
     82             {
     83               AfxMessageBox(_T("接受数据异常"));
     84             }
     85             else
     86             {
     87                 //AfxMessageBox(_T("有消息"));
     88             }
     89 
     90             //把echoBuffer转格式成wchar_t
     91             size_t len = strlen(echoBuffer) + 1;
     92             size_t converted = 0;
     93             wchar_t *WStr;
     94             WStr=(wchar_t*)malloc(len*sizeof(wchar_t));
     95             mbstowcs_s(&converted, WStr, len, echoBuffer, _TRUNCATE);
     96 
     97             //获取对方ip
     98             char *addr = inet_ntoa(ClntAddr.sin_addr);
     99             //把addr转格式成wchar_t
    100             len = strlen(addr) + 1;
    101             wchar_t *address;
    102             address=(wchar_t*)malloc(len*sizeof(wchar_t));
    103             mbstowcs_s(&converted, address, len, addr, _TRUNCATE);
    104 
    105             /*把发送端的ip地址和消息还有换行都存放在buffer里,然后一直往save里追加*/
    106             buffer.Format(_T("【%s】说 :%s\r\n"),address,WStr);
    107             save = save+buffer;
    108             
    109             p->SetDlgItemTextW(IDC_EDIT1,save);
    110             p->SetDlgItemTextW(IDC_EDIT2,NULL);
    111             //p->m_msg = buffer;
    112             //p->UpdateData(false);    
    113     }
    114     Server.Close();
    115 
    116     return 0;
    117 
    118 }
    View Code
    void CMFCUDPDlg::OnOK()
    {
        /*当编辑好发送内容后,直接按回车,就相当于点击了发送按钮*/
        OnBnClickedButton1();
    }

    提示:如果没有换行,记得将编辑控件的属性里的Multiline属性设置为true,然后记得添加滚动条,需要的话设置成readonly。

    感想:我承认里面做了很多烦琐而低效的类型转换。希望有人能指点。化繁为简。

     

  • 相关阅读:
    XToDo未完成内容标记管理器
    FuzzyAutocomplete代码模糊匹配智能提示
    KSImageNamed项目图片智能提示
    Backlight当前行背景高亮显示
    VVDocumenter规范注释生成器
    window.frames[]在Firefox下无法兼容的解决方式
    加密算法(扩展知识:Base64编码)
    Single Pattern(单例模式)
    C语言的基本数据类型长度
    移位操作和二进制知识
  • 原文地址:https://www.cnblogs.com/ligongzi/p/2722597.html
Copyright © 2011-2022 走看看