1. 异步套接字编程:
//①自定义消息
#define UM_SOCK WM_USER+1
//②做一个消息响应函数的申明
afx_msg voidOnSock(WPARAM, LPARAM);
//在析构函数当中关闭套接字,释放与套接字相关的资源
CChatDlg::~CChatDlg()
{
if(m_socket)
closesocket(m_socket);
}
BOOL CChatDlg::OnInitDialog()
{
InitSocket();
return TRUE; // return TRUE unless you set thefocus to a control
}
BOOLCChatDlg::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(6000);
if(SOCKET_ERROR == bind(m_socket, (SOCKADDR*)&addrSock,sizeof(SOCKADDR) ))
{
MessageBox("绑定失败!");
return FALSE;
}
//请求一个基于消息的windows网络事件通知
if(SOCKET_ERROR == WSAAsyncSelect(m_socket,m_hWnd, UM_SOCK, FD_READ))
{
MessageBox("注册网络读取事件失败!");
return FALSE;
}
return TRUE;
}
//③消息响应函数
voidCChatDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
//首先要去判断一下是不是网络读取事件发生了,然后再去调用接收
//函数去接收数据。
switch(LOWORD(lParam))
{
case FD_READ:
//定义一个WSABUF结构体的变量
WSABUF wsabuf;
//分配空间
wsabuf.buf = new char[200];
wsabuf.len = 200;
DWORD dwRead;
DWORDdwFlag = 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;
}
//从地址结构体的变量当中取出一个以网络字节序表示的ulong类型
//addrFrom.sin_addr.S_un.S_addr这是一个ulong类型,而我们需要char*
//首先取地址(&),就得到了ulong的指针,加上(char*)就可以得到字符指针类型
pHost = gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4, AF_INET );
//将接收到的数据做一个格式化,取出发送端的IP地址
// str.Format("%s说: %s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
//通过pHost取出主机的名字
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;
}
}
//发送端
voidCChatDlg::OnBtnSend()
{
//接收IP地址
DWORD dwIP;
CString strSend;
//定义一个WSABUF结构体的变量
WSABUF wsabuf;
//接收实际发送的字节数
DWORD dwSend;
//主要时用来保存CString对象当中字符的数目
int len;
CString strHostName;
SOCKADDR_IN addrTo;
HOSTENT* pHost;
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName), strHostName == "")
{
//调用GetAddress得到IP地址
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr = htonl(dwIP);
}
else
{
pHost = gethostbyname(strHostName);
//如何将一个字符指针转换ulong类型呢?
//pHost->h_addr_list[0]可以先将得到的IP地址数据取出来
//现在取出的就是一个字符的指针,而这个字符指针中存放的就是以网络字节序表示的地址
//如何将这个指针转换为一个ulong类型呢?
//既然它是一个字符指针,我们先将它转化为一个DWORD类型指针,指针之间可以相互转换,
//只要它的内存是兼容的就行了。再用一个*取出这个指针所指向的ulong类型的数据
//ulong类型占四个字节。
//①(DWORD*)pHost->h_addr_list[0]先将它转化为DWORD指针,
//②然后再取值:*((DWORD*)pHost->h_addr_list[0])
//对于DWORD指针取值的话,取出四个字节,这四个字节正好是网络字节序表示的ulong类型的地址
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);
//这里不能直接将CString对象赋给它
len = strSend.GetLength();
//GetBuffer可以将一个CString对象转换为一个char* 返回
wsabuf.buf = strSend.GetBuffer(len);
//加一个字节,主要是传递一个\0,让接收端接收的字符有一个/0结尾
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;
}
}
//总结:
//在windows平台下,它的程序的运行都是基于消息的,所以选择异步选择机制
//可以提高编写的网络应用程序的效率。
//在windows平台下,我们要想编写一个高性能的网络应用程序,除了对协议本身
//有所了解以外,还需要了解程序在windows平台下工作的原理。
//我们在编写网络应用程序的时候,因为网络的状况瞬息万变,所以我们在调用
//函数的时候,总是应该对这个函数的返回值做一个判断,如果出错了应该怎么样
//去处理。
//在编写网络应用程序的时候,一定要仔细,要多做实验,基于我们所运行的平台
//的特点,相应的去调整网络应用程序实现的细节,这样才能编写出高性能的网络应用程序。