当前位置:C++技术网 > 资讯 > Winsock异步编程的浅析

Winsock异步编程的浅析

更新时间:2015-08-30 11:44:40浏览次数:1+次

     windows套接字继承自Berkeley套接口,这些函数都是同步的,每个函数在执行下一条语句前必须完成。winsock规范包含了基本的Berkeley套接口函数,并结合windows的消息机制做了扩展,那就是异步winsock。

    windows的消息是异步的,他们不是按照事先定义的顺序发生的。当你的程序开始一个任务时,可以告诉windows在任务完成时发送一条消息,收到消息根据任务完成的结果再决定下一步做什么?

    同步模型中,当处理当执行一些需要话费很长时间才能完成的功能时,程序会被阻塞,不能执行其他操作,儿异步套接口则不同,它会调用WSAAsyncSelelct(),是程序不会发生阻塞。该函数提供异步I./O模型,是函数不会阻塞。

    我们讲下这个函数:

int WSAAsyncSelect(
  _In_ SOCKET       s,
  _In_ HWND         hWnd,
  _In_ unsigned int wMsg,
  _In_ long         lEvent
);
第一个参数套接字,第二个就是窗口句柄我们用MFC共有的窗口句柄m_hWnd,来调用,第三个是应用程序响应消息,第四个是网络事件。
   当我们进行套接字的消息响应时,我们要加上以下代码:
    .....//省略代码
#define WM_SOCKET WM_USER+100
......
........
//省略代码
protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CMyDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnConnect(); afx_msg void OnSend(); //}}AFX_MSG afx_msg void OnSocket(WPARAM wParam,LPARAM lParam);//加上的代码 DECLARE_MESSAGE_MAP() };
BEGIN_MESSAGE_MAP(CSERVEDlg, CDialog)
	//{{AFX_MSG_MAP(CSERVEDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_SEND, OnSend)
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_SOCKET,OnSocket)//加上的代码
END_MESSAGE_MAP()
所以第三个参数我们在这里就是WM_SOCKET,第四个参数,windows程序中我们需要传参,LPRAM和WPARAM,但具体是那个参数相应我们的网络事件呢,我们理理思路,当套接口指定的发生网络事件的应用程序收到wMsg时,wParam是发生网络事件的套接口句柄,而lParam则是进行网络事件的传递。
网络事件有:
Event: FD_ACCEPT
Event: FD_ADDRESS_LIST_CHANGE
Event: FD_GROUP_QOS
Event: FD_OOB
Event: FD_QOS
Event: FD_READ
Event: FD_WRITE
第一个在服务器端使用,函数accept相应,而第六个则是函数recv响应,最后一个是send()函数响应,当我们进行多条网络事件时,我们需要进行按位或,看代码:



::WSAAsyncSelect(s,this->m_hWnd,WM_SOCKET,FD_READ | FD_ACCEPT);
用switch..case..语句来实现。

void CSERVEDlg::OnSocket(WPARAM wParam,LPARAM lParam)
{
	CString str13;
	char cs[100]={0};
	switch(lParam)
	{
	case FD_ACCEPT:
		{
			int lenth=sizeof(addr1);
			s1=accept(s,(sockaddr*)&addr1,&lenth);
			str13+=::inet_ntoa(addr.sin_addr);
			str13+="\r\n登录\r\n";
			GetDlgItem(IDC_TEXT)->SetWindowText(str13);
		}
		break;
	case FD_READ:
		{
			CString num="";
			::recv(s1,cs,sizeof(cs),0);
			GetDlgItem(IDC_TEXT)->GetWindowText(num);
			num+="\r\n";
			num+="对你说";
			num+=(LPTSTR)cs;
			GetDlgItem(IDC_TEXT)->SetWindowText(num);
			break;
		}
	}
}