MFC 创建异步套接字的网络聊天程序
1.首先包含 winsock2.h
2.工程-设置 链接 ws2_32.lib
3.在app类的InitInstance()中加载套接字库 因为要用2.2的版本 所以AfxSocketInit()不用 不过AfxSocketInit加载1.1版本很方便 并且可以省去上面两步骤
BOOL CChat16App::InitInstance()
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData))
{
AfxMessageBox("套接字库加载失败");
return FALSE;
}
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
AfxMessageBox("套接字库加载版本不一致");
WSACleanup();
return FALSE;
}
4.Dlg类中 加入SOCKET m_sock,CString recvBuf成员
并且写下此代码
BOOL CChat16Dlg::InitSocket()
{
m_sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);
if (INVALID_SOCKET==m_sock)
{
MessageBox("套接字创建失败");
return FALSE;
}
SOCKADDR_IN addr;
addr.sin_family=AF_INET;
addr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addr.sin_port=htons(6000);
if(bind(m_sock,(SOCKADDR*)&addr,sizeof(SOCKADDR))==SOCKET_ERROR)
{
MessageBox("套接字绑定失败");
return FALSE;
}
if(WSAAsyncSelect(m_sock,m_hWnd,UM_SOCK,FD_READ)) //登记网络事件 等网络读取事件发生以UM_SOCK消息通知对话框窗口
{
MessageBox("网络事件登记失败");
return FALSE;
}
return TRUE;
}
5.自定义消息的编写
void CChat16Dlg::OnSock(WPARAM wParam,LPARAM lParam)
{
CString strTemp;
WSABUF wsabuf;
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD recvCz;
DWORD flags=0;
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
CString strFmt;
HOSTENT *pHost;
switch(LOWORD(lParam))
{
case FD_READ:
WSARecvFrom(m_sock,&wsabuf,1,&recvCz,&flags,(SOCKADDR*)&addrFrom,&len,NULL,NULL);
strTemp=wsabuf.buf;
delete[] wsabuf.buf;
strTemp+="\r\n";
// strFmt.Format("%s:%s",inet_ntoa(addrFrom.sin_addr),strTemp);
pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET); //第一个参数要求char*的网络字节序 第二个参数 因为地址族是AF_INET 必须4
strFmt.Format("%s:%s",pHost->h_name,strTemp);
recvBuf+=strFmt;
break;
}
SetDlgItemText(IDC_EDIT_RECV,recvBuf);
}
6.
BOOL CChat16Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
InitSocket(); //调用刚刚的函数
7.
发送端 的编写
void CChat16Dlg::OnSendbtn()
{
// TODO: Add your control notification handler code here
CString sendBuf;
WSABUF wsabuf;
DWORD sendCz;
SOCKADDR_IN addrTo;
DWORD dwIp;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->GetAddress(dwIp);
GetDlgItemText(IDC_EDIT_SEND,sendBuf);
SetDlgItemText(IDC_EDIT_SEND,"");
wsabuf.buf=sendBuf.GetBuffer(sendBuf.GetLength()+1);
wsabuf.len=sendBuf.GetLength()+1;
addrTo.sin_family=AF_INET;
// addrTo.sin_addr.S_un.S_addr=htonl(dwIp);
addrTo.sin_port=htons(6000);
CString strHostName;
if (GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName=="")
{
addrTo.sin_addr.S_un.S_addr=htonl(dwIp);
}
else
{
hostent *pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)(pHost->h_addr_list[0])); //h_addr_list[0]是一个字符指针 因为是网络字节序可以先将其转为DWORD* 而后按DWORD类型取值
}
if(WSASendTo(m_sock,&wsabuf,1,&sendCz,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))
{
MessageBox("发送失败");
}
}
8.最后
void CChat16Dlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
closesocket(m_sock); //关闭套接字
WSACleanup(); //清除加载的版本
CDialog::OnClose();
}