IOCP完成端口通俗讲义与项目实战

什么是IOCP完成端口?

我们可以把IOCP完成端口(以下统称IOCP)理解为Windows下性能最高的网络编程技术,本文讲解该技术的基本知识,以及如何使用该技术开发高性能的网络软件。
IOCP本质上就是Windows内核提供的一种请求队列+通知队列,我们把各种耗时的网络操作请求投递到请求队列,IOCP具体怎么去完成这些网络操作我们不管,IOCP完成后会把结果放到通知队列里,我们就去通知队列里获取结果然后处理。

什么是同步和异步?

同步就是,你跟朋友聊天,你发完一句话后,一直盯着这个聊天窗口等待朋友回复,这样你就只能同时跟一个朋友聊天。如果有10个朋友同时找你,要么你就只能让后面9个朋友排队等着,等你跟第一个朋友聊完了再聊下一个,要么就需要再请9个人帮你聊天。
异步就是,你跟朋友聊天,你发完一句话后,就去做其他事情,等听到消息通知后,再去回复朋友。这样即使10个朋友同时找你,你一个人也能聊得过来。所以异步的效率是不是比同步高很多?
我们最开始接触网络编程时,一般都是用同步模式。比如我要发起TCP连接,就会调用connect函数,调用过程中会阻塞等待,直到连接成功或者失败才会返回,然后判断函数的返回值。这就是同步模式,最简单但是效率也最低。
IOCP是一种异步模式,我调用connect函数后,调用会马上返回而且没有结果。我就可以先去执行其他任务,直到我得到通知说connect请求已经有结果了,我才去处理。

IOCP的使用步骤

虽然要完全掌握IOCP比较难,但它的使用步骤其实非常简单,关键就这么几步:创建IOCP关联SOCKET投递网络操作请求获取IO通知。我们以发起TCP连接为例,详细讲解这些步骤。

1.创建IOCP

我们先使用WSAStartup启动套接字库。

WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);

然后我们创建一个IOCP实例,后续的操作将使用这个实例的句柄。

HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

2.关联SOCKET

进行网络操作肯定要先创建SOCKET,但跟平时不同的是,我们需要创建一个支持异步模式的特殊SOCKET,即给SOCKET加上重叠标志WSA_FLAG_OVERLAPPED

SOCKET socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);

然后我们把这个SOCKET关联到IOCP中去,这样以后对该SOCKET发起的网络操作都会由IOCP处理。

CreateIoCompletionPort((HANDLE)socket, hIOCP, socket, 0);

3.投递网络操作请求

每个投递到IOCP中的请求都需要包含一个编号信息,IOCP完成请求后在通知里也会包含这个编号信息。通过这个编号信息才能知道哪个通知对应哪个请求,这个编号信息就保存在重叠结构里。
我们不能调用普通的connect函数来发起连接,而是需要调用一个支持重叠结构的ConnectEx函数。但是这个函数默认是没有加载的,我们需要先加载这个函数。

GUID guidConn = WSAID_CONNECTEX;
LPFN_CONNECTEX pfnConnectEx = NULL;
DWORD dw = 0;
WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConn, sizeof(guidConn), &pfnConnectEx, sizeof(pfnConnectEx), &dw, NULL, NULL);

跟调用connect函数发起连接不同的是,调用ConnextEx函数发起连接前,需要先把SOCKET绑定好本地端口。我们可以绑定0,这样系统就会自动分配本地端口。

sockaddr_in addrBind = {0};
addrBind.sin_family = AF_INET;
addrBind.sin_addr.s_addr = htonl(INADDR_ANY);
addrBind.sin_port = htons(0);
bind(socket ,(SOCKADDR*)&addrBind, sizeof(addrBind));

然后调用ConnectEx函数发起连接,注意最后一个参数就是重叠结构。这时发起连接请求和相应的重叠结构,就一起投递到IOCP中去了。

sockaddr_in addrConn = {0};
addrConn.sin_family = AF_INET;
addrConn.sin_addr.S_un.S_addr = inet_addr("112.53.42.52");
addrConn.sin_port = htons(80);
OVERLAPPED overlap = {0};
pfnConnectEx(socket, (sockaddr*)&addrConn, sizeof(addrConn), NULL, 0, NULL, &overlap);

4.获取IO通知

最后我们向IOCP获取通知,如果IOCP通知队列里暂时还没有通知,则会阻塞等待

DWORD dwBytes;
SOCKET socketGet;
OVERLAPPED* overlapGet;
BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, (LPOVERLAPPED*)&overlapGet, INFINITE);

获取到通知后,我们可以根据bIOSucc来判断是否连接成功,至于其他参数怎样使用,我们后续再详细讲解。

网络操作类型

本文仅讲解TCP相关的网络操作类型,除了我们前面讲的发起连接,要投递到IOCP中处理的网络操作还有:发送数据接收数据接受连接

●发送数据

比如我们要发送的数据指针为pData,数据大小为uiDataSize,我们需要先把数据复制到WSABUF缓冲区中,然后调用WSASend函数发送数据。

WSABUF buf = {0};
buf.len = uiDataSize;
buf.buf = (char*)malloc(uiDataSize);
memcpy(buf.buf, pData, uiDataSize);

OVERLAPPED overlap = {0};
WSASend(socket, &buf, 1, NULL, 0, &overlap, NULL);

●接收数据

接收数据前需要先准备好WSABUF接收缓冲区,比如我申请了1024字节的缓冲区,然后调用WSARecv函数接收数据。

WSABUF buf = {0};
buf.buf = (char*)malloc(1024);
buf.len = 1024;

DWORD dwFlags = 0;
OVERLAPPED overlap = {0};
WSARecv(socket, &buf, 1, NULL, &dwFlags, &overlap, NULL);

等获取到通知说接收数据请求已经完成后,缓冲区里才会有数据。

●接受连接

我们需要调用AcceptEx函数来接受连接,但是这个函数默认是没有加载的,我们先加载这个函数。

GUID guidAccept = WSAID_ACCEPTEX;
LPFN_ACCEPTEX pfnAcceptEx = NULL;
DWORD dw = 0;
WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAccept, sizeof(guidAccept), &pfnAcceptEx, sizeof(pfnAcceptEx), &dw, NULL, NULL);

跟调用accept函数接受连接不同的是,调用AcceptEx函数前,需要为接受的连接提前准备好SOCKET。而且还需要一个存放对方地址信息的缓冲区,接受到连接后可以调用GetAcceptExSockaddrs函数解析出对方的地址信息。

SOCKET socketAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
void* pBuf = malloc(sizeof(sockaddr_in) + 16);
OVERLAPPED overlap = {0};
pfnAcceptEx(socket, socketAccept, pBuf, 0, 0, sizeof(sockaddr_in) + 16, NULL, &overlap);

网络操作上下文

我们前面讲到每个投递到IOCP中的网络操作请求都需要包含一个相应的重叠结构,IOCP完成网络操作请求后在通知里也会包含这个相应的重叠结构。
以下代码在调用ConnectEx函数发起连接时,会把重叠结构overlap的指针一起投递到IOCP中。等连接操作完成后,调用GetQueuedCompletionStatus函数获取IO通知时,获取到的overlapGet就是之前overlap的指针。

OVERLAPPED overlap = {0};
pfnConnectEx(socket, (sockaddr*)&addrConn, sizeof(addrConn), NULL, 0, NULL, &overlap);

OVERLAPPED* overlapGet;
BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, &overlapGet, INFINITE);

如果我们要向IOCP同时投递发起连接和接收数据两个请求,当我们获取到IO通知后,怎么区分这是发起连接的通知,还是接收数据的通知呢?我们可以把重叠结构扩展一下,扩展成方便我们使用的自定义结构体,比如定义一个iOperateType成员来表示网络操作类型,这个自定义结构体就叫网络操作的上下文

typedef struct Context
{
    OVERLAPPED    overlap;
    int           iOperateType;
}SContext;

以后我们就不向IOCP投递重叠结构的指针了,而是改成投递上下文的指针。因为我们把重叠结构放在了上下文的第一位,这样重叠结构的首地址和上下文的首地址就是相等的。所以在投递上下文的指针时,其实就相当于投递了重叠结构的指针,而获取IO通知时获取到的重叠结构的指针,也相当于获取到了上下文的指针。
以下代码用iOperateType为1表示发起连接,iOperateType为2表示接收数据,向IOCP同时投递了发起连接和接收数据两个请求。在获取到IO通知后,就可以判断contextGet->iOperateType是什么类型的IO通知,然后根据类型做相应的处理。

SContext contextConn = {0};
contextConn.iOperateType = 1;
pfnConnectEx(socket, (sockaddr*)&addrConn, sizeof(addrConn), NULL, 0, NULL, (OVERLAPPED*)&contextConn);

SContext contextRecv = {0};
contextRecv.iOperateType = 2;
WSARecv(socket, &buf, 1, NULL, &dwFlags, (OVERLAPPED*)&contextRecv, NULL);

SContext* contextGet;
BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, (LPOVERLAPPED*)&contextGet, INFINITE);

if (contextGet->iOperateType == 1)
{
}
if (contextGet->iOperateType == 2)
{
}

工作线程

我们前面讲IOCP的使用步骤时,最后一步获取IO通知是会阻塞等待的。我们需要创建专门的线程来不停地获取IO通知,然后处理网络操作的结果,这个线程就叫IOCP的工作线程

DWORD WINAPI _threadIOCPWork(LPVOID param)
{
    while (true)
    {
        DWORD dwBytes;
        SOCKET socketGet;
        SContext* contextGet;
        BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, (LPOVERLAPPED*)&contextGet, INFINITE);
	}

    return 0;
}

一个工作线程最多只能占用一个CPU内核,为了发挥最大性能,最好是有几个CPU内核就创建几个工作线程。

SYSTEM_INFO si;
GetSystemInfo(&si);
for (DWORD i = 0; i < si.dwNumberOfProcessors; i++)
{
    CreateThread(NULL, 0, _threadIOCPWork, NULL, 0, NULL);
}

回调函数

根据软件设计的原则,我们在工作线程中应该只负责获取IO通知和处理网络操作的结果,而后续的业务逻辑可以通过回调函数的方式交给业务模块去处理。
比如我们要处理前面讲的发起连接和接收数据的结果,可以先定义两个回调函数,然后在工作线程中进行回调。

typedef void (*PFNConn)(BOOL bSucc);
typedef void (*PFNRecv)(void* pData, unsigned int uiDataSize);

PFNConn pfnConn;
PFNRecv pfnRecv;

DWORD WINAPI _threadIOCPWork(LPVOID param)
{
    while (true)
    {
        DWORD dwBytes;
        SOCKET socketGet;
        SContext* contextGet;
        BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, (LPOVERLAPPED*)&contextGet, INFINITE);

        if (contextGet->iOperateType == 1)
        {
            pfnConn(bIOSucc);
        }
        if (contextGet->iOperateType == 2)
        {
            pfnRecv(buf.buf, dwBytes);
        }
	}

    return 0;
}

提前把pfnConn和pfnRecv设置成业务模块的回调函数,就可以在业务模块中处理业务逻辑了。

上下文设计

上下文作为IOCP中最重要的概念,设计好上下文才能用好IOCP。除了前面讲的overlap和iOperateType这两个基础成员,我们还可以往上下文里添加更多成员。
但是不同类型的网络操作需要的成员是不一样的,我们可以用一个基础上下文衍生出各种不同类型的上下文。比如添加接收缓冲区和接收回调函数成员,定义出接收上下文。

typedef struct Context
{
    OVERLAPPED    overlap;
    int           iOperateType;
}SContext;

typedef struct RecvContext
    : SContext
{
    WSABUF     buf;
    PFNRecv    pfnRecv;
}SRecvContext;

这样我们就可以用接收上下文来投递接收数据请求,获取IO通知时先获取基础上下文的指针,然后根据iOperateType转换成接收上下文的指针。

SRecvContext contextRecv = {0};
contextRecv.iOperateType = 2;
contextRecv.buf.buf = (char*)malloc(1024);
contextRecv.buf.len = 1024;
contextRecv.pfnRecv = pfnRecv;
WSARecv(socket, &contextRecv.buf, 1, NULL, &dwFlags, (OVERLAPPED*)&contextRecv, NULL);

DWORD dwBytes;
SContext* contextGet;
BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, (LPOVERLAPPED*)&contextGet, INFINITE);

if (contextGet->iOperateType == 2)
{
    SRecvContext* contextRecv = (SRecvContext*)contextGet;
    contextRecv->pfnRecv(contextRecv->buf.buf, dwBytes);
}

网络类设计

接下来我们正式开始编码,我们先把IOCP的TCP网络功能实现。我把功能分成了3个类,分别为:TCP类、上下文缓冲区类、套接字缓冲区类。
代码地址:https://download.csdn.net/download/jaye8090/9740955

●TCP类

对外的接口都在这里定义,主要的功能也在这个类里实现。

/******************************************************************************
TCP类
功能:
	用IOCP技术实现的异步TCP类,支持客户端和服务器的常用功能。
作者:
	佳也 2623168833 jaye8090@qq.com
******************************************************************************/
class CTCP
{
	/**************************************************************************
	绑定
	说明:
		绑定端口
	参数:
		socket		输出值。套接字。
		usPort		端口
	返回:
		绑定端口成功返回true,否则返回false。
	**************************************************************************/
	bool Bind(SOCKET & socket, unsigned short usPort);

	/**************************************************************************
	监听
	说明:
		监听套接字,并指定接受连接的回调函数。
	参数:
		socket			套接字
		pfnAccept		接受回调函数
		pThis			回调this指针
	**************************************************************************/
	void Listen(SOCKET socket, ContextBuf::PFNAccept pfnAccept, void * pThis);

	/**************************************************************************
	接收
	说明:
		接收数据,并指定接收数据的回调函数。
		接受到连接、连接成功后,必须调用此接口才会开始接收数据。
	参数:
		socket		套接字
		pfnRecv		接收回调函数
		pThis		回调this指针
	**************************************************************************/
	void Recv(SOCKET socket, ContextBuf::PFNRecv pfnRecv, void * pThis);

	/**************************************************************************
	连接
	说明:
		创建连接,并指定连接通知的回调函数。
	参数:
		socket		输出值。套接字。
		ulIP		IP
		usPort		端口
		pfnConn		连接回调函数
		pThis		回调this指针
	**************************************************************************/
	void Conn(SOCKET & socket, unsigned long ulIP, unsigned short usPort
		, ContextBuf::PFNConn pfnConn, void * pThis);

	/**************************************************************************
	发送
	说明:
		发送数据
	参数:
		socket			套接字
		pData			数据
		uiDataSize		数据大小
	**************************************************************************/
	void Send(SOCKET socket, void * pData, unsigned int uiDataSize);

	/**************************************************************************
	关闭
	说明:
		关闭套接字,可停止监听端口、断开连接。
		连接失败、连接断开后,必须调用此接口关闭套接字。
	参数:
		socket		套接字
	**************************************************************************/
	void Close(SOCKET socket);

	/**************************************************************************
	停止
	说明:
		停止所有端口的监听、断开所有连接、清空所有资源。
	**************************************************************************/
	void Stop(void);
};

●上下文缓冲区类

上下文缓冲区类主要管理上下文的申请和释放,并定义好网络操作类型、回调函数、各种类型的上下文。

/******************************************************************************
操作类型定义
******************************************************************************/
typedef enum OperateType
{
	OPERATE_ACCEPT,		//接受
	OPERATE_CONN,		//连接
	OPERATE_SEND,		//发送
	OPERATE_RECV,		//接收
}EOperateType;

/******************************************************************************
接受回调函数定义
参数:
	socket		套接字,监听结束则为INVALID_SOCKET。
	ulIP		IP
	pThis		回调this指针
******************************************************************************/
typedef void (* PFNAccept)(SOCKET socket, unsigned long ulIP, void * pThis);

/******************************************************************************
连接回调函数定义
参数:
	bSucc		连接是否成功
	strErr		错误串
	pThis		回调this指针
******************************************************************************/
typedef void (* PFNConn)(bool bSucc, string strErr, void * pThis);

/******************************************************************************
接收回调函数定义
参数:
	pData			数据,连接断开则为NULL。
	uiDataSize		数据大小
	pThis			回调this指针
******************************************************************************/
typedef void (* PFNRecv)(void * pData, unsigned int uiDataSize, void * pThis);

/******************************************************************************
上下文
******************************************************************************/
typedef struct Context
{
	OVERLAPPED			overlap;			//重叠结构
	EOperateType		eOperateType;		//操作类型
}SContext;

/******************************************************************************
接受上下文
******************************************************************************/
typedef struct AcceptContext
	: SContext
{
	SOCKET			socket;			//套接字
	void			* pBuf;			//缓冲区
	PFNAccept		pfnAccept;		//接受回调函数
	void			* pThis;		//回调this指针
}SAcceptContext;

/******************************************************************************
连接上下文
******************************************************************************/
typedef struct ConnContext
	: SContext
{
	PFNConn		pfnConn;		//连接回调函数
	void		* pThis;		//回调this指针
}SConnContext;

/******************************************************************************
接收上下文
******************************************************************************/
typedef struct RecvContext
	: SContext
{
	WSABUF		buf;			//缓冲区
	PFNRecv		pfnRecv;		//接收回调函数
	void		* pThis;		//回调this指针
}SRecvContext;

/******************************************************************************
发送上下文
******************************************************************************/
typedef struct SendContext
	: SContext
{
	WSABUF		buf;		//缓冲区
}SSendContext;

然后定义上下文缓冲区类和接口。

/******************************************************************************
上下文缓冲区类
功能:
	实现上下文的分配、释放和清空。
作者:
	佳也 2623168833 jaye8090@qq.com
******************************************************************************/
class CContextBuf
{
//基本接口
public:
	/**************************************************************************
	分配接受
	说明:
		分配接受上下文
	参数:
		pfnAccept		接受回调函数
		pThis			回调this指针
	返回:
		接受上下文
	**************************************************************************/
	ContextBuf::SAcceptContext * AllocAccept(PFNAccept pfnAccept
		, void * pThis);

	/**************************************************************************
	分配连接
	说明:
		分配连接上下文
	参数:
		pfnConn		连接回调函数
		pThis		回调this指针
	返回:
		连接上下文
	**************************************************************************/
	ContextBuf::SConnContext * AllocConn(PFNConn pfnConn
		, void * pThis);

	/**************************************************************************
	分配接收
	说明:
		分配接收上下文
	参数:
		pfnRecv		接收回调函数
		pThis		回调this指针
	返回:
		接收上下文
	**************************************************************************/
	ContextBuf::SRecvContext * AllocRecv(PFNRecv pfnRecv
		, void * pThis);

	/**************************************************************************
	分配发送
	说明:
		分配发送上下文
	参数:
		pData			数据
		uiDataSize		数据大小
	返回:
		发送上下文
	**************************************************************************/
	ContextBuf::SSendContext * AllocSend(void * pData
		, unsigned int uiDataSize);

	/**************************************************************************
	释放
	说明:
		释放上下文
	参数:
		pContext		上下文
	**************************************************************************/
	void Free(ContextBuf::SContext * pContext);

	/**************************************************************************
	清空
	说明:
		释放所有分配的上下文
	**************************************************************************/
	void Clear(void);
};

●套接字缓冲区类

套接字缓冲区类专门管理所有套接字的申请和释放。

/******************************************************************************
套接字缓冲区类
功能:
	实现套接字的创建、关闭和清空。
作者:
	佳也 2623168833 jaye8090@qq.com
******************************************************************************/
class CSocketBuf
{
//基本接口
public:
	/**************************************************************************
	创建
	说明:
		创建一个套接字
	返回:
		套接字
	**************************************************************************/
	SOCKET Create(void);

	/**************************************************************************
	创建
	说明:
		创建一个套接字,并绑定端口。
	参数:
		usPort		端口,0表示由系统随机分配端口。
	返回:
		绑定成功返回套接字,否则返回INVALID_SOCKET。
	**************************************************************************/
	SOCKET Create(unsigned short usPort);

	/**************************************************************************
	关闭
	说明:
		关闭一个套接字
	参数:
		socket		套接字
	**************************************************************************/
	void Close(SOCKET socket);

	/**************************************************************************
	清空
	说明:
		关闭所有创建的套接字
	**************************************************************************/
	void Clear(void);
};

项目实战

接下来我们使用IOCP来开发一个支持Socks4和Socks5的高并发服务器程序,只需要少数几个工作线程就能处理成千上万个并发连接,并且CPU占用一直保持在很低的水平。Socks协议要处理的核心业务就是把用户连接和目标连接桥接起来,并转发两个连接之间的通信数据,我专门用一个通道模块来处理这个核心业务。
代码地址:https://download.csdn.net/download/jaye8090/86787017

●通道模块

通道模块放在Channel目录中,由3个类组成:通道类、目标连接类、用户连接类。通道类是上层,管理目标连接类和用户连接类。
我把用户到目标的中转称为桥接,一个桥接由一个用户连接和一个目标连接组成,定义如下:

/******************************************************************************
桥接结构体
******************************************************************************/
typedef struct Bridge
{
	CCriticalSection		csLock;				//互斥锁
	CUserConn				* pUserConn;		//用户连接
	CDstConn				* pDstConn;			//目标连接
}SBridge;

通道类的功能就是管理用户到目标的桥接。通道类会监听Socks端口,收到一个Socks连接请求则会生成一个用户到目标的桥接。并检查连接的活跃度,关闭长时间无通信的死连接。

/******************************************************************************
通道类
功能:
	管理用户到目标的桥接
作者:
	佳也 2623168833 jaye8090@qq.com
******************************************************************************/
class CChannel
{
	/**************************************************************************
	删除用户连接
	参数:
		pBridge		桥接
	**************************************************************************/
	void DelUserConn(Channel::SBridge * pBridge);

	/**************************************************************************
	删除目标连接
	参数:
		pBridge		桥接
	**************************************************************************/
	void DelDstConn(Channel::SBridge * pBrige);

	/**************************************************************************
	获取连接数
	说明:
		获取通道的连接数
	返回:
		连接数
	**************************************************************************/
	unsigned int GetConnCnt(void);

	/**************************************************************************
	关闭
	说明:
		关闭套接字,停止监听端口,关闭所有连接,停止线程。
	**************************************************************************/
	void Close(void);

	/**************************************************************************
	是否已经关闭
	说明:
		桥接表是否为空,线程是否已经退出。
	返回:
		已经关闭返回true,否则返回false。
	**************************************************************************/
	bool IsClose(void);
};

目标连接类用于处理和目标的数据收发。建立跟目标主机的连接,连接成功或者失败后通知用户。并向目标主机发送数据,收到数据后转给用户。

/******************************************************************************
目标连接类
功能:
	处理和目标的数据收发
作者:
	佳也 2623168833 jaye8090@qq.com
******************************************************************************/
class CDstConn
{
	/**************************************************************************
	通信发送
	说明:
		向目标发送通信数据
	参数:
		pData			数据
		uiDataSize		数据大小
	**************************************************************************/
	void CommSend(void * pData, unsigned int uiDataSize);

	/**************************************************************************
	关闭
	说明:
		关闭套接字,断开连接。
	**************************************************************************/
	void Close(void);
};

用户连接类用于处理和Socks用户的数据收发。接受用户的Socks连接,处理用户的Socks业务请求,并建立对应的目标连接。把用户发来的数据转给目标,并把目标发来的数据转给用户。每个桥接都通过用户连接来判断活跃度,用户连接不活跃,则关闭整个桥接。

/******************************************************************************
用户连接类
功能:
	处理和SOCKS用户的数据收发
作者:
	佳也 2623168833 jaye8090@qq.com
******************************************************************************/
class CUserConn
{
	/**************************************************************************
	连接响应
	说明:
		给用户的目标连接响应
	**************************************************************************/
	void ConnResponse(void);

	/**************************************************************************
	通信接收
	说明:
		给用户的目标通信数据
	参数:
		data		数据
	**************************************************************************/
	void CommRecv(CDataPack & data);

	/**************************************************************************
	检查活跃
	说明:
		检查连接是否活跃
	**************************************************************************/
	void CheckAlive(void);

	/**************************************************************************
	关闭
	说明:
		关闭套接字,断开连接。
	**************************************************************************/
	void Close(void);
};

●其他模块

DataProcess目录为数据处理模块,分为数据打包类和数据解析类,主要用于处理Socks协议的打包和解析。
Ptl目录为协议模块,用于实现Socks4和Socks5协议的细节。
Lock目录为锁模块,AutoLock为自动锁类,用户多线程加锁。
TCP目录为网络模块,与前面介绍的网络模块不同的是,多了个桥接控制类,用于解决用户连接和目标连接之间的网速同步问题。

●演示效果

最终编译出服务器程序,并用浏览器测试效果。

下载地址:https://download.csdn.net/download/jaye8090/86793228

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值