您的位置:首页 > 其它

MFC笔记之多线程聊天室

2014-07-18 22:34 260 查看
新手刚接触,跟着孙鑫老师视频一步一步的做。从VC6.0到VS2010好像并不是那么顺利,下面记录下一点收获。

网络编程的一般步骤:

1声明套接字版本(WSAStartup);2创建套接字(socket);3绑定套接字(bind);4发送接收(sendto/recvfrom);5关闭(closesocket)

第1~3步代码如下:

CString error;
WORD wver;
wver=MAKEWORD(1,1);
WSAData data;
if(0!=WSAStartup(wver,&data))
{
  error.Format(_T("声明版本失败,错误代码:%d!"),WSAGetLastError());
  MessageBox(error);
}

ms=socket(2,SOCK_DGRAM,0);
if(ms==INVALID_SOCKET)
{
  error.Format(_T("创建套接字失败,错误代码:%d!"),WSAGetLastError());
  MessageBox(error);
}

SOCKADDR_IN msaddr;
msaddr.sin_family=AF_INET;
msaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
msaddr.sin_port=htons(6000);
int len=sizeof(msaddr);
if(SOCKET_ERROR==bind(ms,(SOCKADDR*)&msaddr,len))
{
  error.Format(_T("绑定套接字失败,错误代码:%d!"),WSAGetLastError());
  MessageBox(error);
}


这段代码要写到OnInitDialog()里;其中ms定义为的SOCKET型成员变量。

既然要用到多线程,这里就先插入一点多线程的知识。

HANDLE hThread1;
hThread1=CreateThread(NULL,0,fun1pro,(LPVOID)ppr,0,NULL);
CloseHandle(hThread1);


其中fun1pro为新线程的入口函数,ppr为传入新线程的参数结构体指针;参数结构体根据需要自行定义。然后是线程函数的实现,里面具体实现socket的接收显示。并且在VS2010中线程函数返回值不能为空,这里我用的DWORD类型;且最好声明成静态成员函数。

DWORD WINAPI CMy0712Dlg::fun1pro(LPVOID lpParameter)
{
SOCKET sock;
HWND hw;
CString error;
sock=((pr*)lpParameter)->s;
hw=((pr*)lpParameter)->hs;
CString cbuf,tbuf;
TCHAR buf[100]={0};
TCHAR temp[120]={0};
CString ttt,sss;
SOCKADDR_IN oaddr;
int len=sizeof(SOCKADDR);
while (TRUE)
{ int a=recvfrom(sock,(char*)&buf,100,0,(SOCKADDR*)&oaddr,&len);
if(SOCKET_ERROR==a)
{
error.Format(_T("接受失败,错误代码:%d!"),WSAGetLastError());
AfxMessageBox(error);
break;
}
else if(a==0)
{
error.Format(_T("socket已经关闭!"));
AfxMessageBox(error);
break;
}
else
{
wsprintf(temp,_T("He said: %s"),buf);
memset(buf,0,100);
sss=_T("");
if(!::PostMessageA(hw,WM_RECV,0,(LPARAM)temp))
{
error.Format(_T("消息传递失败,错误代码:%d!"),GetLastError());
AfxMessageBox(error);
error.GetLength();
}
}
}
return 0;
}


这里将接收到的数据存在了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);


LRESULT CMy0712Dlg::OnRecv(WPARAM wParam,LPARAM lParam)
{

CString cs(((TCHAR*)lParam));
CString temp;
GetDlgItemText(IDC_EDIT1,temp);
int i=temp.GetLength();
if(i!=0)
{temp+="\r\n";}
temp+=cs;
SetDlgItemText(IDC_EDIT1,temp);
return 0;
}


发送函数做到了一个按钮的响应函数里

void CMy0712Dlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
CString cs,error,temp;
SOCKADDR_IN addr;
addr.sin_family=AF_INET;
addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addr.sin_port=htons(6000);
int len=sizeof(addr);
GetDlgItemText(IDC_EDIT2,cs);
int i=sendto(ms,(char*)cs.GetBuffer(cs.GetLength()*2),cs.GetLength()*2+2,0,(SOCKADDR*)&addr,sizeof(SOCKADDR));
if(SOCKET_ERROR==i)
{
error.Format(_T("数据发送失败,错误代码:%d!"),WSAGetLastError());
MessageBox(error);
}
cs=_T("");
SetDlgItemText(IDC_EDIT2,cs);
}


这就基本完成了所有代码,但是在默认使用Unicode字符集的VS2010中还是有点小问题的。其中sendto发送了发送缓存两倍的空间,具体在代码中体现。

参考资料:http://blog.163.com/lj_2005/blog/static/458654220115662544227/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: