您的位置:首页 > 理论基础 > 计算机网络

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

2014-10-11 14:04 435 查看
网络聊天室程序(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地址
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: