本例采用Socket实现局域网通信。
开发环境:XP+VS2005+MFC
源码已上传到CSDN资源中:http://download.csdn.net/detail/segen_jaa/4638910,也可私信给我,单独发送。
关键API:WSAAsyncSelect,以网络事件为基础,基于消息实现异步通信。
说明:同一socket上,两次调用WSAAsyncSelect,第二次注册消息会覆盖第一次消息。
1、服务端
效果如下图。
主对话框,响应FD_ACCEPT(接受客户端)|FD_READ(获取客户端信息)|FD_CLOSE(客户端关闭)消息。
#define WM_NETWORK WM_USER+100
LRESULT OnNetwork(WPARAM wParam, LPARAM lParam);
ON_MESSAGE(WM_NETWORK,&CAsyncServerDlg::OnNetwork)
{
......
//注册感兴趣的网络事件
int nAsyncRet = WSAAsyncSelect(m_sListen, m_hWnd, WM_NETWORK, FD_ACCEPT|FD_READ|FD_CLOSE);
if (SOCKET_ERROR == nAsyncRet)
{
CAsyncFunc::SetAppendText(this, IDC_EDIT_DESC, _T("注册网络事件失败!"));
return;
}
......
}
LRESULT CAsyncServerDlg::OnNetwork(WPARAM wParam, LPARAM lParam)
{
SOCKET sClient = (SOCKET)wParam;
WORD netEvent = WSAGETSELECTEVENT(lParam);
WORD error = WSAGETSELECTERROR(lParam);
if (error!=0)
{
CString strErrorInfo = _T("");
strErrorInfo.Format(_T("Error code: %d"), error);
CAsyncFunc::SetAppendText(this, IDC_EDIT_DESC, strErrorInfo);
return -1;
}
switch(netEvent)
{
case FD_ACCEPT: OnAccept(); break;
case FD_READ: OnFDRead(sClient); break;
case FD_CLOSE: OnFDClose(sClient); break;
}
return 0;
}
void CAsyncServerDlg::OnFDRead(SOCKET sClient)
{
//该客户端首次收到消息,启动对话框
CAsyncTalkMng::GetInstance()->StartTalkDlg(sClient, this);
}
void CAsyncServerDlg::OnFDClose(SOCKET sClient)
{
//删除列表条目
int nItemCount = m_ClientList.GetCount();
for (int i = 0; i < nItemCount; i++)
{
SOCKET sTemp = (SOCKET)m_ClientList.GetItemData(i);
if (sTemp == sClient)
{
m_ClientList.DeleteString(i);
break;
}
}
//关闭连接
CAsyncTalkMng::GetInstance()->RemoveClient(sClient);
//通知对话框,连接已关闭
CAsyncTalkMng::GetInstance()->StopTalkDlg(sClient);
}
void CAsyncServerDlg::OnAccept()
{
struct sockaddr_in client;
int iAddrSize = sizeof(client);
SOCKET sClient = accept(m_sListen, (struct sockaddr*)&client, &iAddrSize);
if (sClient == INVALID_SOCKET)
{
CString strErrorInfo = _T("");
strErrorInfo.Format(_T("accept() failed:%d"), WSAGetLastError());
CAsyncFunc::SetAppendText(this, IDC_EDIT_DESC, strErrorInfo);
return;
}
char* sClientIP = inet_ntoa(client.sin_addr);
wstring wsClientIP = CAsyncFunc::AnsiToUnicode(string(sClientIP));
CString strClientIP = wsClientIP.c_str();
CString strIPAddr = _T("");
strIPAddr.Format(_T("%s:%d"), strClientIP, ntohs(client.sin_port));
CString strTipInfo = _T("");
strTipInfo += _T("accepted client:");
strTipInfo += strIPAddr;
CAsyncFunc::SetAppendText(this, IDC_EDIT_DESC, strTipInfo);
StClientSock* pClientSock = new StClientSock;
pClientSock->sClient = sClient;
pClientSock->strIPAddr = strIPAddr;
CAsyncTalkMng::GetInstance()->AddClient(pClientSock);
int nItemIndex = m_ClientList.AddString(strIPAddr);
m_ClientList.SetItemData(nItemIndex, sClient);
}
聊天框,响应FD_READ(获取客户端信息)|FD_CLOSE(客户端关闭)消息。
#define WM_NETWORK_TALK WM_USER+101
LRESULT OnNetwork(WPARAM wParam, LPARAM lParam);
void OnFDRead();
void OnFDClose(SOCKET sClient);
ON_MESSAGE(WM_NETWORK_TALK,&CAsyncTalkDlg::OnNetwork)
void CAsyncTalkDlg::InitSocketMsg()
{
int nAsyncRet = WSAAsyncSelect(clientSock.sClient, m_hWnd, WM_NETWORK_TALK, FD_READ|FD_CLOSE);
if (SOCKET_ERROR == nAsyncRet)
{
CAsyncFunc::SetAppendText(this, IDC_EDIT_DESC, _T("注册网络事件失败!"));
return;
}
}
LRESULT CAsyncTalkDlg::OnNetwork(WPARAM wParam, LPARAM lParam)
{
WORD netEvent = WSAGETSELECTEVENT(lParam);
WORD error = WSAGETSELECTERROR(lParam);
if (error!=0)
{
CString strErrorInfo = _T("");
strErrorInfo.Format(_T("Error code: %d"), error);
CAsyncFunc::SetAppendText(this, IDC_EDIT_DESC, strErrorInfo);
return -1;
}
switch(netEvent)
{
case FD_READ: OnFDRead(); break;
case FD_CLOSE: OnFDClose((SOCKET)wParam); break;
}
return 0;
}
void CAsyncTalkDlg::OnFDRead()
{
char szBuff[DEFAULT_BUFFER] = {0};
int ret = recv(clientSock.sClient, szBuff, DEFAULT_BUFFER, 0);
if (0 == ret)
{
return;
}
else if (SOCKET_ERROR == ret)
{
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, _T("recv() failed"));
return;
}
szBuff[ret] = '\0';
wstring wsRecvInfo = CAsyncFunc::AnsiToUnicode(string(szBuff));
CString strRecvInfo = _T("");
strRecvInfo += clientSock.strIPAddr;
strRecvInfo += _T(":");
strRecvInfo += (CString)(wsRecvInfo.c_str());
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, strRecvInfo);
}
void CAsyncTalkDlg::OnFDClose(SOCKET sClient)
{
if (NULL == m_pMsgFlow)
{
return;
}
m_pMsgFlow->OnFDClose(sClient);
}
2、客户端
效果图如下。
主要代码,响应FD_READ(获取服务端消息)|FD_CLOSE(服务端socket关闭)消息。
#define WM_NETWORK WM_USER+100
LRESULT OnNetwork(WPARAM wParam, LPARAM lParam);
void OnFDRead();
void OnFDClose();
ON_MESSAGE(WM_NETWORK,&CAsyncClientDlg::OnNetwork)
{
......
//注册感兴趣的网络事件
int nAsyncRet = WSAAsyncSelect(m_sClient, m_hWnd, WM_NETWORK, FD_READ|FD_CLOSE);
if (SOCKET_ERROR == nAsyncRet)
{
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, _T("注册网络事件失败!"));
return;
}
......
}
LRESULT CAsyncClientDlg::OnNetwork(WPARAM wParam, LPARAM lParam)
{
//SOCKET s = (SOCKET)wParam;
WORD netEvent = WSAGETSELECTEVENT(lParam);
WORD error = WSAGETSELECTERROR(lParam);
if (error!=0)
{
CString strErrorInfo = _T("");
strErrorInfo.Format(_T("Error code: %d"), error);
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, strErrorInfo);
return -1;
}
switch(netEvent)
{
case FD_READ: OnFDRead(); break;
case FD_CLOSE: OnFDClose(); break;
}
return 0;
}
void CAsyncClientDlg::OnFDRead()
{
char szBuff[DEFAULT_BUFFER] = {0};
int ret = recv(m_sClient, szBuff, DEFAULT_BUFFER, 0);
if (0 == ret)
{
return;
}
else if (SOCKET_ERROR == ret)
{
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, _T("recv() failed"));
return;
}
szBuff[ret] = '\0';
wstring wsRecvInfo = CAsyncFunc::AnsiToUnicode(string(szBuff));
CString strRecvInfo = _T("");
strRecvInfo += _T("服务端:");
strRecvInfo += (CString)(wsRecvInfo.c_str());
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, strRecvInfo);
}
void CAsyncClientDlg::OnFDClose()
{
closesocket(m_sClient);
m_bSocketClose = true;
CAsyncFunc::SetAppendText(this, IDC_EDIT_RECV, _T("服务端已关闭"));
GetDlgItem(IDC_EDIT_SEND)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_SEND)->EnableWindow(FALSE);
}
分享到:
相关推荐
C#+Socket异步传输 基于TCP 编程
一个基于VB.net的异步Socket网络TCP通信
socket网络编程,没有选用线程模式,而是选用的异步的select模型。windows下的WSASelect模型,基于消息传递机制,实现了一个服务器和客户端,聊天
用Socket编程实现电子邮件的发送
自己用MFC对话框程序实现的基于UDP的socket编程示例,分为客户端和服务端,客户端发送一个字符串,服务端接收。代码简单明了,无论是学习还是拿到自己的项目中使用都很好。
socket网络编程 不可多得的资源,包含异步通信和同步通信,多线程的执行程序,节省大量代码
这是一个基于Windows Socket网络编程的一个Win32控制台程序,通过使用异步模式实现服务器端和客户端的通信,服务器端注册套接字读事件,负责在套接字上接收数据,客户端注册发送事件,负责向服务器端发送数据,
Linux下基于C/C++的Socket的阻塞和异步编程实例
在服务端的使用集合CPtrList类用保存客户端的socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端的socket对象,而MFC框架提供了CSocket类,它是一个异步通信的类,所以...
HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中[1] 。为了让使用者能方便快速地学习和使用 HP-Socket ,迅速掌握框架的设计思想和使用方法,特此精心制作了大量 Demo 示例(如...
同步套接字通信 Socket支持下的网上点对点的通信 Socket编程原理 基于TCP协议的发送和接收端 异步套接字 多线程
本教程将向您介绍如何使用 Python 开发基于 socket 的网络应用程序。在本教程中,您将首先学习一些 Python的基础知识,并了解 Python 是如何成为一种很好的网络编程语言的。然后您将着重了解 Python 的基本 socket ...
采用c#编写的基于SOCKET的通信程序,分为客户端和服务端两块,根据相应的IP地址和端口号,实现消息的发送和接收,为异步方式实现。
最近做了一个关于socket的基于TCP协议的异步通信系统--TongXing.DLL;它里面封装了通信的一些比较复杂的方法:1:数据加密解密 2:数据失败自动重发 3:心跳模块 4:客户端网络问题断开自动重连 5:服务器自动拒绝...
两个程序都是基于Select异步模型的,其中服务端还用到了多线程技术,保证了多客户端的连接 都是消息触发和回调的 用多线程就能够保证多客户端的同时连接,要满足更多的客户端连接,要用到线程池模型,有待于更进一步的...
该资源是基于tcp的异步通讯,不是多线程,实现了一服务器多客户端
异步Socket,HTTP(客户端 服务器),WebSocket,和socket.io库。基于NIO而不是线程。
该资源是基于UDP的异步聊天室,一个服务器多个客户端,没有使用多线程
本篇阐述基于TCP通信协议的异步实现。 二、实验平台 Visual Studio 2010 三、异步通信实现原理及常用方法 3.1 建立连接 在同步模式中,在服务器上使用Accept方法接入连接请求,而在客户端则使用Connect方法来...