首页 > 代码库 > MFC笔记之多线程聊天室
MFC笔记之多线程聊天室
新手刚接触,跟着孙鑫老师视频一步一步的做。从VC6.0到VS2010好像并不是那么顺利,下面记录下一点收获。
网络编程的一般步骤:
1声明套接字版本(WSAStartup);2创建套接字(socket);3绑定套接字(bind);4发送接收(sendto/recvfrom);5关闭(closesocket)
第1~3步代码如下:
1 CString error; 2 WORD wver; 3 wver=MAKEWORD(1,1); 4 WSAData data; 5 if(0!=WSAStartup(wver,&data)) 6 { 7 error.Format(_T("声明版本失败,错误代码:%d!"),WSAGetLastError()); 8 MessageBox(error); 9 }10 11 ms=socket(2,SOCK_DGRAM,0);12 if(ms==INVALID_SOCKET)13 {14 error.Format(_T("创建套接字失败,错误代码:%d!"),WSAGetLastError());15 MessageBox(error);16 }17 18 SOCKADDR_IN msaddr;19 msaddr.sin_family=AF_INET;20 msaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);21 msaddr.sin_port=htons(6000);22 int len=sizeof(msaddr);23 if(SOCKET_ERROR==bind(ms,(SOCKADDR*)&msaddr,len))24 {25 error.Format(_T("绑定套接字失败,错误代码:%d!"),WSAGetLastError());26 MessageBox(error);27 }
这段代码要写到OnInitDialog()里;其中ms定义为的SOCKET型成员变量。
既然要用到多线程,这里就先插入一点多线程的知识。
1 HANDLE hThread1;2 hThread1=CreateThread(NULL,0,fun1pro,(LPVOID)ppr,0,NULL);3 CloseHandle(hThread1);
其中fun1pro为新线程的入口函数,ppr为传入新线程的参数结构体指针;参数结构体根据需要自行定义。然后是线程函数的实现,里面具体实现socket的接收显示。并且在VS2010中线程函数返回值不能为空,这里我用的DWORD类型;且最好声明成静态成员函数。
1 DWORD WINAPI CMy0712Dlg::fun1pro(LPVOID lpParameter) 2 { 3 SOCKET sock; 4 HWND hw; 5 CString error; 6 sock=((pr*)lpParameter)->s; 7 hw=((pr*)lpParameter)->hs; 8 CString cbuf,tbuf; 9 TCHAR buf[100]={0};10 TCHAR temp[120]={0};11 CString ttt,sss;12 SOCKADDR_IN oaddr;13 int len=sizeof(SOCKADDR);14 while (TRUE)15 { int a=recvfrom(sock,(char*)&buf,100,0,(SOCKADDR*)&oaddr,&len);16 if(SOCKET_ERROR==a)17 {18 error.Format(_T("接受失败,错误代码:%d!"),WSAGetLastError());19 AfxMessageBox(error);20 break;21 }22 else if(a==0)23 {24 error.Format(_T("socket已经关闭!"));25 AfxMessageBox(error);26 break;27 }28 else29 {30 wsprintf(temp,_T("He said: %s"),buf);31 memset(buf,0,100);32 sss=_T("");33 if(!::PostMessageA(hw,WM_RECV,0,(LPARAM)temp))34 {35 error.Format(_T("消息传递失败,错误代码:%d!"),GetLastError());36 AfxMessageBox(error);37 error.GetLength();38 }39 }40 }41 return 0;42 }
这里将接收到的数据存在了buf里,然后加上格式头存在temp里,通过PostMessage将temp作为自定义消息WM_RECV的lParam传递出去。
这里牵扯到自定义消息的定义
#define WM_RECV WM_USER+1
还有消息映射
ON_MESSAGE(WM_RECV,OnRecv)
消息函数的声明实现
afx_msg LRESULT OnRecv(WPARAM wParam,LPARAM lParam);
1 LRESULT CMy0712Dlg::OnRecv(WPARAM wParam,LPARAM lParam) 2 { 3 4 CString cs(((TCHAR*)lParam)); 5 CString temp; 6 GetDlgItemText(IDC_EDIT1,temp); 7 int i=temp.GetLength(); 8 if(i!=0) 9 {temp+="\r\n";}10 temp+=cs;11 SetDlgItemText(IDC_EDIT1,temp);12 return 0;13 }
发送函数做到了一个按钮的响应函数里
1 void CMy0712Dlg::OnBnClickedButton2() 2 { 3 // TODO: 在此添加控件通知处理程序代码 4 CString cs,error,temp; 5 SOCKADDR_IN addr; 6 addr.sin_family=AF_INET; 7 addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 8 addr.sin_port=htons(6000); 9 int len=sizeof(addr);10 GetDlgItemText(IDC_EDIT2,cs);11 int i=sendto(ms,(char*)cs.GetBuffer(cs.GetLength()*2),cs.GetLength()*2+2,0,(SOCKADDR*)&addr,sizeof(SOCKADDR));12 if(SOCKET_ERROR==i)13 {14 error.Format(_T("数据发送失败,错误代码:%d!"),WSAGetLastError());15 MessageBox(error);16 }17 cs=_T("");18 SetDlgItemText(IDC_EDIT2,cs); 19 }
这就基本完成了所有代码,但是在默认使用Unicode字符集的VS2010中还是有点小问题的。其中sendto发送了发送缓存两倍的空间,具体在代码中体现。
参考资料:http://blog.163.com/lj_2005/blog/static/458654220115662544227/
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。