WSAAsyncSelect基于异步通知的网络socket通信案例一

服务端

消息通知和WSAAsyncSeect
WSAAsyncSelect函数自动把套接字设为非阻塞模式,并且为套接字绑定一个窗口句柄,当有网络事件发送时,便向这个窗口发送消息。

FD_READ	 套接字接收到对方发送过来的数据包,表明这时可以去读套接字了(recv用)
FD_WRITE 数据缓冲区满后再次变空时,WinSock接口通关该通知码通知应用程序。表示可以继续发送数据了(短时间内发送数据过多,便会造成数据缓冲区变满)
FD_ACCEPT 监听中的套接字检测到有连接进入
FD_CONNECT如果用套接字去连接对方的主机,当连接动作完成以后会接收到这个通知码
FD_CLOSE  检测到套接字对应的链接被关闭

#define WSAGETSELECTERROR(lParam) HIWORD(lParam)	//高字为出错代码
#define WSAGETSELCTEVENT(lParam) LOWORD(lParam)		//低字为通知码


stdafx.h

#ifndef MFCTEST_HEAD
#define MFCTEST_HEAD
#pragma once
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <afxwin.h>
#include <afxframewndex.h>
#include <Winsock2.h>
#include <assert.h>
#pragma comment (lib,"ws2_32.lib")



class CMyApp:public CWinApp
{
public:
	//构造函数
	CMyApp();
	//析构函数
	virtual ~CMyApp();

	//重载函数
public:
	//初始函数
	virtual BOOL InitInstance();
};



class CMyWindow : public CFrameWndEx
{
public:
	CButton												m_button;								 //按钮
	SOCKET												m_socket;								//连接句柄
	SOCKET												m_ClientSocket;					//客户端句柄	

public:
	//构造函数
	CMyWindow();
	//析构函数
	virtual ~CMyWindow();

	//虚函数
public:
	//命令响应消息
	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);


	// 消息函数
protected:
	// 网络读取
	LRESULT OnSocketNotifyRead(WPARAM wParam, LPARAM lParam);
	// 网络关闭
	LRESULT OnSocketNotifyClose(WPARAM wParam, LPARAM lParam);
	// 网络连接
	LRESULT OnSocketNotifyAccept(WPARAM wParam, LPARAM lParam);

	//消息映射
public:
	//创建消息
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	//网络消息
	afx_msg LRESULT OnSocket(WPARAM  wParam, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
};



#endif

afxmain.cpp

#include "stdafx.h"

CMyApp myapp;

#define						WM_SOCKET							WM_USER+1					//网络消息
#define						IDC_START							1012								 //按钮定义

//构造函数
CMyApp::CMyApp()
{

}

//析构函数
CMyApp::~CMyApp()
{

}

//初始函数
BOOL CMyApp::InitInstance()
{
	m_pMainWnd = new CMyWindow();
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}



BEGIN_MESSAGE_MAP(CMyWindow, CFrameWndEx)
	ON_WM_CREATE()
	ON_MESSAGE(WM_SOCKET, OnSocket)
END_MESSAGE_MAP()

//构造函数
CMyWindow::CMyWindow()
{
	//设置变量
	m_ClientSocket = INVALID_SOCKET;
	m_socket= INVALID_SOCKET;

	//创建窗口
	Create(NULL, TEXT("My Window"));
}
//析构函数
CMyWindow::~CMyWindow()
{
	WSACleanup();
}

//命令响应消息
BOOL CMyWindow::OnCommand( WPARAM wParam, LPARAM lParam )
{
	int wmId=LOWORD(wParam);
	switch (wmId)
	{
	case IDC_START:
		{
			MessageBox(TEXT("测试一下哈"),TEXT("提示"),MB_OK);
			return true;
		}
		break;
	default:
		return true;
	}

	return __super::OnCommand(wParam,lParam);

}

//创建事件
int CMyWindow::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
	__super::OnCreate(lpCreateStruct);

	//居中窗口
	SetActiveWindow();
	SetForegroundWindow();
	CenterWindow(GetParent());

	//创建按钮
	RECT rect={0,0,50,30};
	m_button.Create(TEXT("按钮"),WS_CHILD|WS_VISIBLE,rect,this,IDC_START);


	//启动使用ws2.dll的
	WORD wVersionRequested = MAKEWORD(2, 2);
	WSADATA lpWSAData = { 0 };
	WSAStartup(wVersionRequested, &lpWSAData);

	//创建socket
	m_socket = socket(AF_INET, SOCK_STREAM, 0);

	//绑定端口
	SOCKADDR_IN addr = { 0 };
	addr.sin_addr.S_un.S_addr =INADDR_ANY;
	addr.sin_family = AF_INET;
	addr.sin_port = 8012;
	if(bind(m_socket, (SOCKADDR*)&addr, sizeof(addr))== SOCKET_ERROR)
		throw TEXT("绑定端口失败");

	//绑定窗口
	int iErrorCode = WSAAsyncSelect(m_socket, this->m_hWnd, WM_SOCKET, FD_READ  | FD_ACCEPT |FD_CLOSE);
	if (iErrorCode == SOCKET_ERROR) throw TEXT("绑定内部窗口错误");

	//监听
	listen(m_socket, 5);

	return true;
}

//网络消息
LRESULT CMyWindow::OnSocket(WPARAM  wParam, LPARAM lParam)
{

	switch (WSAGETSELECTEVENT(lParam))
	{
	case FD_ACCEPT:		//网络连接
	{
		return OnSocketNotifyAccept(wParam, lParam);
	}
	case FD_READ: // 数据读取
	{
		return OnSocketNotifyRead(wParam, lParam);
	}
	case FD_CLOSE: // 网络关闭
	{
		return OnSocketNotifyClose(wParam, lParam);
	}
	}

	return 0;
}

// 网络读取
LRESULT CMyWindow::OnSocketNotifyRead(WPARAM wParam, LPARAM lParam)
{
	try
	{
		ASSERT(m_ClientSocket != INVALID_SOCKET);
		if (m_ClientSocket == INVALID_SOCKET)return false;

		// 读取数据
		char  szText[1024] = { 0 };
		int iRetCode = recv(m_ClientSocket, szText, 1024, 0);
		if (iRetCode == SOCKET_ERROR) throw TEXT("网络连接关闭,读取数据失败");

		char szSendText[64] = { "这是服务端发送的消息" };
		send(m_ClientSocket, szSendText, 64, 0);
	}
	catch (...)
	{
		closesocket(m_ClientSocket);
	}
	return true;
}



// 网络关闭
LRESULT CMyWindow::OnSocketNotifyClose(WPARAM wParam, LPARAM lParam)
{
	closesocket(m_ClientSocket);
	return true;
}

// 网络连接
LRESULT CMyWindow::OnSocketNotifyAccept(WPARAM wParam, LPARAM lParam)
{
	SOCKADDR_IN clientaddr = { 0 };
	INT nBufferSize = sizeof(clientaddr);
	m_ClientSocket = accept(m_socket, (SOCKADDR*)&clientaddr, &nBufferSize);
	//退出判断
	if (m_ClientSocket == INVALID_SOCKET) return false;
	return true;
}



客户端

WHSocketHead.h

#pragma once
#pragma pack(1)
#include <Winsock2.h>
#include <assert.h>
#pragma comment (lib,"ws2_32.lib")

#pragma pack(1)

//网络命令
struct TCP_Command
{
	WORD							wMainCmdID;							//主命令码
	WORD							wSubCmdID;							//子命令码
};
#pragma pack()



//网络状态
#define					SOCKET_STATUS_IDLE			0									//空闲状态
#define					SOCKET_STATUS_WAIT			1									//等待状态
#define					SOCKET_STATUS_CONNECT	2									//连接状态

//关闭原因
#define				SHUT_REASON_INSIDE				0									//内部原因
#define				SHUT_REASON_NORMAL			1									//正常关闭
#define				SHUT_REASON_REMOTE			2									//远程关闭
#define				SHUT_REASON_TIME_OUT		3									//网络超时
#define				SHUT_REASON_EXCEPTION		4									//异常关闭

//网络接口
__interface ITCPSocketSink
{
	//网络事件
public:
	//连接事件
	virtual bool OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode) = NULL;
	//关闭事件
	virtual bool OnEventTCPSocketShut(WORD wSocketID, BYTE cbShutReason) = NULL;
	//读取事件
	virtual bool OnEventTCPSocketRead(WORD wSocketID, TCP_Command Command, VOID * pData, WORD wDataSize) = NULL;
};

stdafx.h

#ifndef MFCTEST_HEAD
#define MFCTEST_HEAD
#pragma once
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <afxwin.h>
#include <afxframewndex.h>
#include "WHSocketHead.h"



//

class CMyApp:public CWinApp
{
public:
	//构造函数
	CMyApp();
	//析构函数
	virtual ~CMyApp();

	//重载函数
public:
	//初始函数
	virtual BOOL InitInstance();
};



class CMyWindow : public CFrameWndEx
{
public:
	CButton												m_button;								 //按钮
	SOCKET												m_socket;								//连接句柄
	BYTE													m_cbSocketStatus;				//网络状态
	WORD												m_wSocketID;						//网络标识


public:
	//构造函数
	CMyWindow();
	//析构函数
	virtual ~CMyWindow();

	//虚函数
public:
	//命令响应消息
	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);

	//辅助函数
protected:
	// 关闭连接
	void CloseSocket(BYTE cbShutReason);

	// 消息函数
protected:
	// 网络读取
	LRESULT OnSocketNotifyRead(WPARAM wParam, LPARAM lParam);
	// 网络发送
	LRESULT OnSocketNotifyWrite(WPARAM wParam, LPARAM lParam);
	// 网络关闭
	LRESULT OnSocketNotifyClose(WPARAM wParam, LPARAM lParam);
	// 网络连接
	LRESULT OnSocketNotifyConnect(WPARAM wParam, LPARAM lParam);

	//消息映射
public:
	//创建消息
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	//网络消息
	afx_msg LRESULT OnSocket(WPARAM  wParam, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
};

<pre name="code" class="cpp">#include "stdafx.h"

CMyApp myapp;

#define						WM_SOCKET							WM_USER+1					//网络消息
#define						IDC_START							1012								 //按钮定义

//构造函数
CMyApp::CMyApp()
{

}

//析构函数
CMyApp::~CMyApp()
{

}

//初始函数
BOOL CMyApp::InitInstance()
{
	m_pMainWnd = new CMyWindow();
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}



BEGIN_MESSAGE_MAP(CMyWindow, CFrameWndEx)
	ON_WM_CREATE()
	ON_MESSAGE(WM_SOCKET, OnSocket)
END_MESSAGE_MAP()

//构造函数
CMyWindow::CMyWindow()
{

	//设置变量
	m_socket= INVALID_SOCKET;
	m_wSocketID = NULL;
	m_cbSocketStatus = SOCKET_STATUS_IDLE;

	//创建窗口
	Create(NULL, TEXT("My Window"));
}
//析构函数
CMyWindow::~CMyWindow()
{
	WSACleanup();
}

//命令响应消息
BOOL CMyWindow::OnCommand( WPARAM wParam, LPARAM lParam )
{
	int wmId=LOWORD(wParam);
	switch (wmId)
	{
	case IDC_START:
		{
			MessageBox(TEXT("测试一下哈"),TEXT("提示"),MB_OK);
			return true;
		}
		break;
	default:
		return true;
	}

	return __super::OnCommand(wParam,lParam);

}

//创建事件
int CMyWindow::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
	__super::OnCreate(lpCreateStruct);

	//居中窗口
	SetActiveWindow();
	SetForegroundWindow();
	CenterWindow(GetParent());

	//创建按钮
	RECT rect={0,0,50,30};
	m_button.Create(TEXT("按钮"),WS_CHILD|WS_VISIBLE,rect,this,IDC_START);

	//启动使用ws2.dll的
	WORD wVersionRequested = MAKEWORD(2, 2);
	WSADATA lpWSAData = { 0 };
	WSAStartup(wVersionRequested, &lpWSAData);

	//创建socket
	m_socket = socket(AF_INET, SOCK_STREAM, 0);
	m_wSocketID = (WORD)m_socket;
	int iErrorCode = WSAAsyncSelect(m_socket, this->m_hWnd, WM_SOCKET, FD_READ   | FD_CONNECT | FD_CLOSE);
	if (iErrorCode == SOCKET_ERROR) throw TEXT("绑定内部窗口错误");

	//连接服务器
	SOCKADDR_IN addr = { 0 };
	addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addr.sin_family = AF_INET;
	addr.sin_port = 8012;
	iErrorCode = connect(m_socket, (SOCKADDR*)&addr, sizeof(addr));
	if (iErrorCode == SOCKET_ERROR)
	{
		iErrorCode = WSAGetLastError();
		TCHAR szBuffer[64] = { 0 };
		if (iErrorCode != WSAEWOULDBLOCK)
		{
			_sntprintf_s(szBuffer, sizeof(szBuffer), TEXT("连接发生错误,错误代码 %d"), iErrorCode);
			throw szBuffer;
		}
		else if (iErrorCode == WSAEWOULDBLOCK)
		{
			_sntprintf_s(szBuffer, sizeof(szBuffer), TEXT("从操作返回的时候没有数据正在排队等待从套接字读取非阻塞无法立即完成的插座 %d"), iErrorCode);
			OutputDebugString(szBuffer);
		}
	}
	// 设置变量
	m_cbSocketStatus = SOCKET_STATUS_WAIT;

	char szText[64] = { "这是客户端发送的消息" };
	send(m_socket, szText, 64, 0);
	return true;
}

//网络消息
LRESULT CMyWindow::OnSocket(WPARAM  wParam, LPARAM lParam)
{

	switch (WSAGETSELECTEVENT(lParam))
	{
		case FD_CONNECT: // 网络连接
		{
			return OnSocketNotifyConnect(wParam, lParam);
		}
		case FD_READ: // 数据读取
		{
			return OnSocketNotifyRead(wParam, lParam);
		}
		case FD_CLOSE: // 网络关闭
		{
			return OnSocketNotifyClose(wParam, lParam);
		}
	}

	return 0;
}
// 网络读取
LRESULT CMyWindow::OnSocketNotifyRead(WPARAM wParam, LPARAM lParam)
{
	try
	{
		// 读取数据
		char szRecvText[1024] = { 0 };
		int iRetCode = recv(m_socket, szRecvText, 1024, 0);
		if (iRetCode == SOCKET_ERROR) throw TEXT("网络连接关闭,读取数据失败");

		// 处理数据
		//bool bSuccess = m_pITCPSocketSink->OnEventTCPSocketRead(m_wSocketID, Command, pDataBuffer, wDataSize);
		//if (bSuccess == false) throw TEXT("网络数据包处理失败");
	}
	catch (...)
	{
		closesocket(m_socket);
	}
	return true;
}


// 网络关闭
LRESULT CMyWindow::OnSocketNotifyClose(WPARAM wParam, LPARAM lParam)
{
	// 关闭连接
	ASSERT(m_socket != INVALID_SOCKET);
	if (m_socket == INVALID_SOCKET)return true;

	m_cbSocketStatus = SOCKET_STATUS_IDLE;
	WSAAsyncSelect(m_socket, GetSafeHwnd(), WM_SOCKET, 0);
	closesocket(m_socket);
	m_socket = INVALID_SOCKET;
	m_cbSocketStatus = SOCKET_STATUS_IDLE;

	//通知事件
	//try { m_pITCPSocketSink->OnEventTCPSocketShut(m_wSocketID, SHUT_REASON_NORMAL); }
	//catch (...) {}
	return true;
}

// 网络连接
LRESULT CMyWindow::OnSocketNotifyConnect(WPARAM wParam, LPARAM lParam)
{
	// 判断状态
	int iErrorCode = WSAGETSELECTERROR(lParam);
	if (iErrorCode == 0) m_cbSocketStatus = SOCKET_STATUS_CONNECT;
	else CloseSocket(SHUT_REASON_TIME_OUT);

	// 发送通知
	//m_pITCPSocketSink->OnEventTCPSocketLink(m_wSocketID, iErrorCode);
	return true;
}

// 关闭连接
void CMyWindow::CloseSocket(BYTE cbShutReason)
{
	// 关闭连接
	ASSERT(m_socket != INVALID_SOCKET);
	if (m_socket == INVALID_SOCKET)return;

	m_cbSocketStatus = SOCKET_STATUS_IDLE;
	WSAAsyncSelect(m_socket, GetSafeHwnd(), WM_SOCKET, 0);
	closesocket(m_socket);
	m_socket = INVALID_SOCKET;
	m_cbSocketStatus = SOCKET_STATUS_IDLE;

	return;
}

#endif

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值