APIsocket,VS2010,windows非阻塞模式异步套接字编程(看孙鑫视频有感)

作者在windows+vs2010写的,UDP,异步套接字。

windows socket有两种模式阻塞式和非阻塞式。

阻塞模式下,windows socket 会一直等待下去,线程会一直阻塞在这里。所以可以考虑使用多线程,创建线程,在线程中死循环,不断recvfrom(),然后PostMessage(),发送消息到消息队列,消息在主线程处理。(参考孙鑫老师Lesson15的Chat程序)

非阻塞模式下,可以利用WSAAsyncSelect()函数。WSAAsyncSelect(SOCKET s,HWND hWnd,usigned int wMsg,long lEvent)。参数lEvent指明应用程序感兴趣的网络事件的组合。该函数能够自动给窗口句柄发送消息(即参数mMsg),并自动将套接字设置为非阻塞模式。然后定义消息,在MESSAGE_MAP里把消息和消息响应函数函数关联起来,最后完成消息响应函数。(参考Lesson16)
写非阻塞模式程序时候发现问题。
1.VC6.0里可以将wMsg的消息响应函数返回值设置为void,但是在VS2010里面会报错error C2440: “static_cast”: 无法从“void (__thiscall CChatMessageDlg::* )(WPARAM,LPARAM)”转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”。
为解决问题,在VS2010中将返回值设置为LRESULT。响应函数的参数lParam的低字节(用LOWORD(lParam)来取)里面保存了网络事件的类型。
2.采用WSA的socket的函数写以上程序的时候,出现了内存错误。作者插了断点,发现消息响应的WSARecvFrom没有接收到信息,准备接收信息的WSABUF变量仍然为空。
为解决问题,作者将有WSA前缀的socket函数换成socket函数(WSAAsyncSelect函数保留),运行OK。
下面附上代码:

1.初始化套接字函数

bool CChatMessageDlg::InitSocket(void)
{
	m_socket=socket(AF_INET,SOCK_DGRAM,0);//增加的扩展函数  与 socket()一样
	if ( INVALID_SOCKET ==m_socket)
	{
		MessageBox("socket failed!");
	}
	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)))
	{
		closesocket(m_socket);
		MessageBox("bind 失败");
		return false;
	}

	if (SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_SOCK,FD_READ))
	{
		MessageBox("注册网路读取事件 失败!");
		return false;
	}
	return true;
}
该函数直接在OnInitDialog中调用即可。

2.Dialog.h头文件中define 消息

#define WM_SOCK WM_USER+1
3.Message_Map中

ON_MESSAGE(WM_SOCK,&CChatMessageDlg::OnSock)
4.消息响应函数

LRESULT CChatMessageDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
	//MessageBox(" onsock");
	switch(LOWORD(lParam))
	{
	case FD_READ:
		{
			
			char recvbuf[200];
			char tempbuf[300];
			int retval;

			sockaddr_in addrfrom;
			int len=sizeof(addrfrom);

			retval=recvfrom(m_socket,recvbuf,200,0,(sockaddr*)&addrfrom,&len);
			if (SOCKET_ERROR==retval)
			{

				return false;
			}
			CString str;
			CString strTemp;
			str.Format("%s说:%s",inet_ntoa(addrfrom.sin_addr),recvbuf);
			str+="\r\n";
			GetDlgItemText(IDC_EDIT_RECV,strTemp);//取出原有的消息
			str+=strTemp;
			SetDlgItemText(IDC_EDIT_RECV,str);
			break;
		}
		
	}
	return 0;
}

5.响应发送按钮的函数

void CChatMessageDlg::OnBnClickedBtnSend()
{
	//MessageBox("send ms");
	// TODO: 在此添加控件通知处理程序代码
	DWORD dwIP;//接收IP地址
	((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

	SOCKADDR_IN addrTo;
	addrTo.sin_addr.S_un.S_addr=htonl(dwIP);//转化为网络字节序
	addrTo.sin_family=AF_INET;
	addrTo.sin_port=htons(6000);

	CString strSend;
	GetDlgItemText(IDC_EDIT_SEND,strSend);
	int len;
	len=strSend.GetLength()+1;
	
	
	sendto(m_socket,strSend,strSend.GetLength()+1,0,(sockaddr*)&addrTo,sizeof(addrTo));



	SetDlgItemText(IDC_EDIT_SEND,"");//清空 发送编辑框
}

6.运行结果







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值