作者在windows+vs2010写的,UDP,异步套接字。
写非阻塞模式程序时候发现问题。
1.VC6.0里可以将wMsg的消息响应函数返回值设置为void,但是在VS2010里面会报错error C2440: “static_cast”: 无法从“void (__thiscall CChatMessageDlg::* )(WPARAM,LPARAM)”转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”。
为解决问题,在VS2010中将返回值设置为LRESULT。响应函数的参数lParam的低字节(用LOWORD(lParam)来取)里面保存了网络事件的类型。
2.采用WSA的socket的函数写以上程序的时候,出现了内存错误。作者插了断点,发现消息响应的WSARecvFrom没有接收到信息,准备接收信息的WSABUF变量仍然为空。
为解决问题,作者将有WSA前缀的socket函数换成socket函数(WSAAsyncSelect函数保留),运行OK。
下面附上代码:
windows socket有两种模式阻塞式和非阻塞式。
阻塞模式下,windows socket 会一直等待下去,线程会一直阻塞在这里。所以可以考虑使用多线程,创建线程,在线程中死循环,不断recvfrom(),然后PostMessage(),发送消息到消息队列,消息在主线程处理。(参考孙鑫老师Lesson15的Chat程序)
写非阻塞模式程序时候发现问题。
1.VC6.0里可以将wMsg的消息响应函数返回值设置为void,但是在VS2010里面会报错error C2440: “static_cast”: 无法从“void (__thiscall CChatMessageDlg::* )(WPARAM,LPARAM)”转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”。
为解决问题,在VS2010中将返回值设置为LRESULT。响应函数的参数lParam的低字节(用LOWORD(lParam)来取)里面保存了网络事件的类型。
2.采用WSA的socket的函数写以上程序的时候,出现了内存错误。作者插了断点,发现消息响应的WSARecvFrom没有接收到信息,准备接收信息的WSABUF变量仍然为空。
为解决问题,作者将有WSA前缀的socket函数换成socket函数(WSAAsyncSelect函数保留),运行OK。
下面附上代码:
1.初始化套接字函数
bool CChatMessageDlg::InitSocket(void)
{
m_socket=socket(AF_INET,SOCK_DGRAM,0);//增加的扩展函数 与 socket()一样
if ( INVALID_SOCKET ==m_socket)
{
MessageBox("socket failed!");
}
SOCKADDR_IN addrSock;
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);
if(SOCKET_ERROR==bind(m_socket,(sockaddr*)&addrSock,sizeof(sockaddr)))
{
closesocket(m_socket);
MessageBox("bind 失败");
return false;
}
if (SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_SOCK,FD_READ))
{
MessageBox("注册网路读取事件 失败!");
return false;
}
return true;
}
该函数直接在OnInitDialog中调用即可。
2.Dialog.h头文件中define 消息
#define WM_SOCK WM_USER+1
3.Message_Map中
ON_MESSAGE(WM_SOCK,&CChatMessageDlg::OnSock)
4.消息响应函数
LRESULT CChatMessageDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
//MessageBox(" onsock");
switch(LOWORD(lParam))
{
case FD_READ:
{
char recvbuf[200];
char tempbuf[300];
int retval;
sockaddr_in addrfrom;
int len=sizeof(addrfrom);
retval=recvfrom(m_socket,recvbuf,200,0,(sockaddr*)&addrfrom,&len);
if (SOCKET_ERROR==retval)
{
return false;
}
CString str;
CString strTemp;
str.Format("%s说:%s",inet_ntoa(addrfrom.sin_addr),recvbuf);
str+="\r\n";
GetDlgItemText(IDC_EDIT_RECV,strTemp);//取出原有的消息
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
break;
}
}
return 0;
}
5.响应发送按钮的函数
void CChatMessageDlg::OnBnClickedBtnSend()
{
//MessageBox("send ms");
// TODO: 在此添加控件通知处理程序代码
DWORD dwIP;//接收IP地址
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
SOCKADDR_IN addrTo;
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);//转化为网络字节序
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(6000);
CString strSend;
GetDlgItemText(IDC_EDIT_SEND,strSend);
int len;
len=strSend.GetLength()+1;
sendto(m_socket,strSend,strSend.GetLength()+1,0,(sockaddr*)&addrTo,sizeof(addrTo));
SetDlgItemText(IDC_EDIT_SEND,"");//清空 发送编辑框
}
6.运行结果