异步通讯 (MFC)
n Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非阻塞模式下,Winsock函数无论如何都会立即返回。
n Windows Sockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存取策略。
n Windows Sockets的异步选择函数WSAAsyncSelect()提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序相应的窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。
1:声明版本号
在MSDN 中WSAStartup找到:
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return FALSE;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
return FALSE;
}
放到APP 中 InitInstance()初始化实例中
2:把头文件的包含放到预编译-- StdAfx.h中
#include
注意:不要写成winsock.h
3:链接一个库文件
在Porject 的Settings 的Link中加入ws2_32.lib
4:终止对套接字的使用
在 APP 的头文件 加 ~CChatApp();
在 APP的源文件 加
CChatApp::~CChatApp()
{
WSACleanup();
}
5:在 Dlg 中加入全局变量 SOCKET m_socket;
在Dlg 的构造函数中初始化 m_socket=0;
6:释放套接字的有关资源
在 Dlg的头文件 加入 ~CChatDlg();
在Dlg的源文件 加入
CChatDlg::~CChatDlg()
{
if (m_socket)
{
closesocket(m_socket);
}
}
7:初始化套接字库的函数
在Dlg点右键加入Function BOOL InitSocket
BOOL CChatDlg::InitSocket()
{
//创建套结字
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);
if (INVALID_SOCKET==m_socket)
{
MessageBox("创建套接字失败!");
return FALSE;
}
//服务器地址属性
SOCKADDR_IN addrSock;
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(8000);
//套接字和地址绑定
if (SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrSock,sizeof(addrSock)))
{
MessageBox("绑定失败!");
return FALSE;
}
//自定义消息UM_SOCK
if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ))
{
MessageBox("注册网络读取事件失败!");
return FALSE;
}
return TRUE;
}
8:在OnInitDialog() 这个函数去调用 InitSocket();
9:在 Dlg的头文件 加入
#define UM_SOCK WM_USER+1
注意:这个语句后面是不用标点的。
10:做一个消息响应函数的声明:
afx_msg void OnSock(WPARAM,LPARAM);
11:在源文件中的 消息映射
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
//{{AFX_MSG_MAP(CChatDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(UM_SOCK,OnSock) //消息映射
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
12:响应函数的实现
void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_READ:
WSABUF wsabuf;
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwRead;
DWORD dwFlag=0;
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
CString str;
CString strTemp;
HOSTENT *pHost;
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
{
MessageBox("接收数据失败!");
return;
}
pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET);
//str.Format("%s说 :%s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
str.Format("%s说 :%s",pHost->h_name,wsabuf.buf);
str+="/r/n";
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
break;
}
}
13:在发送的按钮
void CChatDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
DWORD dwIP;
CString strSend;
WSABUF wsabuf;
DWORD dwSend;
int len;
CString strHostName;
SOCKADDR_IN addrTo;
HOSTENT* pHost;
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName=="")
{
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
}
else
{
pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)pHost->h_addr_list[0]);
}
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(6000);
GetDlgItemText(IDC_EDIT_SEND,strSend);
len=strSend.GetLength();
wsabuf.buf=strSend.GetBuffer(len);
wsabuf.len=len+1;
SetDlgItemText(IDC_EDIT_SEND,"");
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))
{
MessageBox("发送数据失败!");
return;
}
}