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地址
};
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地址
};
相关文章推荐
- 异步非阻塞套接字Winsock开发网络通信程序的经典入门
- VC:简单聊天室程序2 --- 基于消息的异步套接字
- 网络编程之即时通信程序(聊天室)------(三)客户端登录
- MFC小程序 简易网络聊天室 VS2012 ODBC连接MySql数据库和网络Socket通信
- MFC网络编程,CSocket,网络通信,网络聊天室
- Linux socket网络编程之聊天室(三):select异步通讯实现
- 网络编程之及时通信程序(聊天室)--------(二)服务器端搭建
- linux------tcp---------Linux网络编程一步一步学-异步通讯聊天程序select
- 网络编程之即时通信程序(聊天室)------(四)客户端搭建
- Java网络编程 - 基于UDP协议 实现简单的聊天室程序
- 孙鑫MFC笔记教程(16)--线程同步和异步套接字编程
- 网络编程之即时通信程序(聊天室)------(一)通信流程简介及通信协议定制
- 网络编程——基于消息的异步套接字编程
- 异步非阻塞套接字Winsock开发网络通信程序的经典入门
- 异步非阻塞套接字Winsock开发网络通信程序的经典入门
- Linux socket网络编程之聊天室(三):select异步通讯实现
- 网络编程之及时通信程序(聊天室)--------(二)服务器端搭建
- 网络编程-UDP协议---简单聊天室程序
- Linux网络编程一步一步学-异步通讯聊天程序select
- MFC网络编程,CSocket,网络通信,网络聊天室