异步套接字编程

异步通讯 MFC

n       Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非阻塞模式下,Winsock函数无论如何都会立即返回。

n       Windows Sockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存取策略。

n       Windows Sockets的异步选择函数WSAAsyncSelect()提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序相应的窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。

 

1:声明版本号

MSDN WSAStartup找到:

       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;

       }

放到APP InitInstance()初始化实例中

 

2:把头文件的包含放到预编译-- StdAfx.h

 #include

       注意:不要写成winsock.h

 

3:链接一个库文件

Porject Settings Link中加入ws2_32.lib

 

4:终止对套接字的使用

    APP 的头文件 ~CChatApp();

       APP的源文件

CChatApp::~CChatApp()

{

       WSACleanup();

}

 

5:在 Dlg 中加入全局变量 SOCKET m_socket;

   Dlg 的构造函数中初始化 m_socket=0

 

6:释放套接字的有关资源 

     Dlg的头文件 加入 ~CChatDlg();

       Dlg的源文件 加入

CChatDlg::~CChatDlg()

{

       if (m_socket)

       {

              closesocket(m_socket);

       }

}

 

7:初始化套接字库的函数

Dlg点右键加入Function    BOOL InitSocket

BOOL CChatDlg::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(8000);

 

       //套接字和地址绑定

       if (SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrSock,sizeof(addrSock)))

       {

              MessageBox("绑定失败!");

              return FALSE;

       }

//自定义消息UM_SOCK

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

       {

              MessageBox("注册网络读取事件失败!");

              return FALSE;

       }

 

      return TRUE;

}

 

8:在OnInitDialog() 这个函数去调用 InitSocket()

 

 

9:在 Dlg的头文件 加入

#define UM_SOCK        WM_USER+1

注意:这个语句后面是不用标点的。

 

10:做一个消息响应函数的声明:

afx_msg void OnSock(WPARAM,LPARAM);

 

11:在源文件中的 消息映射

BEGIN_MESSAGE_MAP(CChatDlg, CDialog)

       //{{AFX_MSG_MAP(CChatDlg)

       ON_WM_SYSCOMMAND()

       ON_WM_PAINT()

       ON_WM_QUERYDRAGICON()

       ON_MESSAGE(UM_SOCK,OnSock)   //消息映射

       //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

12:响应函数的实现

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("接收数据失败!");

                     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;

       }

}

 

13:在发送的按钮

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

              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;

       }

      

}

 

你可能感兴趣的:(异步套接字编程)