MFC:异步套接字编程举例—网络聊天室程序

来源:互联网 发布:axure 8.0 mac 破解版 编辑:程序博客网 时间:2024/06/06 10:46
网络聊天室程序(MFC:利用win32的扩展函数):
int WSAStartup(
  WORD wVersionRequested,
  LPWSADATA lpWSAData
);
一、加载套接字库:
//本程序要用到winsock2版本的函数,所以还要自己调用WSAStartup函数。将帮助文档中的例子代码复制
//放到CChatApp的InitInstance()函数中,并作相应修改,还需包含头文件#include <winsock2.h>和链接库
//文件ws2_32.lib(Alt+F7):
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 ); //请求Winsock2.2版本,也是最高版本
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
    return;
}

if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) {        

//    WSACleanup( ); 放到析构函数中

    return false; //false
}
二、在App中增加析构函数终止对套接字库的使用:
CChatApp::~CChatApp()
{
WSACleanup();//终止对套接字的使用
}
三、CChatDlg添加成员变量SOCKET m_socket,并初始化为0,加析构:
CChatDlg::~CChatDlg(){
if(m_socket)
closesocket(m_socket);
}
四、添加初始化套接字库的函数(1、创建套接字 2、绑定套接字 3、注册网络读取事件),并在OnInitDialog函数中调用:
BOOL CChatDlg::InitSocket()// 在OnInitDialog 函数中调用
{
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);//win32的扩展函数(WSA+)创建套接字
if(INVALID_SOCKET==m_socket)
{
MessageBox("创建套接字失败!");
return FALSE;
}
//绑定套接字
SOCKADDR_IN addrSock;
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//4字节 将主机字节顺序转换成网络字节顺序
//inet_addr("136.149.3.49");将点式ip地址转换成四字节的ulong类型
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);//2字节 将主机字节顺序转换成网络字节顺序
if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR))) //绑定套接字
{
MessageBox("绑定失败!");
return FALSE;
}
//接收windows的基于消息的网络事件通知
//消息到来时系统通过WM_SOCK的消息响应函数来通知我们 
  if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ)) //我的另一篇用的是多线程编写
{
MessageBox("注册网络读取事件失败!");
return FALSE;
}
return TRUE;
}
五、自定义消息:
1、#define UM_SOCK WM_USER+1
2、消息响应函数原型的声明:
afx_msg void OnSock(WPARAM,LPARAM);//消息通过参数传递,所以要带参数
3、消息映射:
ON_MESSAGE(UM_SOCK,OnSock)
4、消息响应函数的实现:
void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam) //在消息响应函数中接收消息
{
//首先判断是否网络读取事件发生了,然后调用接收函数接收数据
//wparam标识了socket,low(lparam)标识发生的网络事件,high(lparam)标识了任何错误代码
switch(LOWORD(lParam)){
case FD_READ: //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)) 
// 接收数据(非重叠套接字:后两个为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;
}
}
六、发送端:发送按钮发送消息

void CChatDlg::OnBtnSend() 
{
DWORD dwIP;
CString strSend;
WSABUF wsabuf;
DWORD dwSend;
int len;
CString strHostName;
SOCKADDR_IN addrTo;
HOSTENT* pHost;
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName=="")//如果没有主机名,就用IP地址
{
((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;
}
} //the end;
注:struct hostent {
  char FAR* h_name;
  char FAR* FAR* h_aliases;
  short h_addrtype;
  short h_length;
  char FAR* FAR* h_addr_list;//存放IP地址,一台主机可能有多个IP地址
};





0 0
原创粉丝点击