学孙鑫VC第16课 异步套接字-聊天室示例

 

//----学孙鑫VC第16课 异步套接字-聊天室示例--------------------//

(1)建立一个对话框工程,工程名为Chat,添加接收编辑框控件IDC_EDIT_RECV,发送信息编辑框控件IDC_EDIT_SEND,IP地址控件IDC_IPADDRESS1,发送按钮IDC_BTN_SEND,主机名IDC_EDIT_HOSTNAME

(2) Stdfx.h文件中加入"#include <winsock2.h>"语句

(3) 在使用之前须链接库函数:工程->设置->Link->输入ws2_32.libOK

(4) 编辑BOOL CChatApp::InitInstance()函数,加入加载2.2版本套接字库代码

BOOL CChatApp::InitInstance()

{

       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;

       }

 

       AfxEnableControlContainer();

}

 

(5)BOOL CChatApp类头文件中增加一个析构函数,用于调用WSACleanup()终止对套接字库的使用

class CChatApp : public CWinApp

{

public:

       CChatApp();

       ~CChatApp();//(5)增加一个析构函数

}

(6)编辑析构函数代码

CChatApp::~CChatApp()

{

       WSACleanup();//调用此函数终止对套接字库的使用

}

(7)CChatDlg类中增加SOCKET类型私有变量m_socket,在构造函数中对这个变量进行初始化,m_socket=0;//进行初始化

class CChatDlg : public CDialog

{

       SOCKET m_socket;

}

(8)class CChatDlg类头文件中增加一个析构函数,

class CChatDlg : public CDialog

{

// Construction

public:

       BOOL InitSocket();//(11)调用创建套接字函数

       CChatDlg(CWnd* pParent = NULL);    // standard constructor

       ~CChatDlg();//(8)类头文件中增加一个析构函数,用于判断并关闭套接字

}

(9)编辑析构函数代码,判断并关闭套接字

CChatDlg::~CChatDlg()

{

       if(m_socket)

              closesocket(m_socket);//(8)判断并关闭套接字

}

(10)class CChatDlg类上点右键,增加一个BOOL类的初始化套接字的函数InitSocket()

BOOL CChatDlg::InitSocket()

{

       m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);//WSASocket()----扩展创建套接字函数

       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;

       }

       if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ))

       {

              MessageBox("注册网络读取事件失败!");//WSAAsyncSelect()异步选择函数,注册网络读取事件,请求一个基于消息的网络事件通知

              return FALSE;

       }

 

       return TRUE;

}

(10)BOOL CChatDlg::OnInitDialog()函数中,调用

{

       // TODO: Add extra initialization here

       InitSocket();

}

 

 

 

(11)CChatDlg类头文件中,调用创建套接字函数,并在函数上面增加自定义消息

#define UM_SOCK        WM_USER+1 //(11)定义自定义消息

class CChatDlg : public CDialog

{

// Construction

public:

       BOOL InitSocket();//(11)调用创建套接字函数

       CChatDlg(CWnd* pParent = NULL);    // standard constructor

       ~CChatDlg();//(8)类头文件中增加一个析构函数,用于判断并关闭套接字

}

(12)在头文件消息列表中增加消息响应函数原型声明

protected:

       HICON m_hIcon;

 

       // Generated message map functions

       //{{AFX_MSG(CChatDlg)

       virtual BOOL OnInitDialog();

       afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

       afx_msg void OnPaint();

       afx_msg HCURSOR OnQueryDragIcon();

       afx_msg void OnBtnSend();

       //}}AFX_MSG

       afx_msg void OnSock(WPARAM,LPARAM);//(12)消息响应函数原型声明

       DECLARE_MESSAGE_MAP()

(13)void CChatDlg::DoDataExchange(CDataExchange* pDX)函数下面的消息映射列表中,增加消息映射

 

void CChatDlg::DoDataExchange(CDataExchange* pDX)

{

       CDialog::DoDataExchange(pDX);

       //{{AFX_DATA_MAP(CChatDlg)

              // NOTE: the ClassWizard will add DDX and DDV calls here

       //}}AFX_DATA_MAP

}

 

BEGIN_MESSAGE_MAP(CChatDlg, CDialog)

       //{{AFX_MSG_MAP(CChatDlg)

       ON_WM_SYSCOMMAND()

       ON_WM_PAINT()

       ON_WM_QUERYDRAGICON()

       ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend)

       //}}AFX_MSG_MAP

       ON_MESSAGE(UM_SOCK,OnSock)//(13)增加消息映射

 

(14)接收网络消息响应函数实现

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("接收数据失败!");//WSARecvFrom()----扩展接收数据函数

                     return;

              }

              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);

              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;

       }

}

(15)编辑[发送]按钮的代码

 

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);//得到IP地址

              addrTo.sin_addr.S_un.S_addr=htonl(dwIP);

       }

       else

       {

              pHost=gethostbyname(strHostName);//gethostbyname(strHostName);将一个主机名转换成IP地址

              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("发送数据失败!");//WSASendTo()----发送数据

              return;

       }

      

}

//----异步选择函数-套接字-聊天室示例结束--------------------//

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值