[C++] 纯文本查看 复制代码
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <WinSock2.h>
#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib, "msvcrt.lib")
#include <stdio.h>
#include <mswsock.h>
#include <MSTcpIP.h>
#include <process.h>
#define tcp_server_connt 1
#define tcp_server_recv 2
#define tcp_server_stop 3
#define tcp_server_send 4
#define tcp_server_close 5
#define tcp_client_connt 1
#define tcp_client_recv 2
#define tcp_client_stop 3
#define tcp_client_send 4
#define tcp_client_close 5
#define tcp_len 65535
typedef void(__stdcall *onServer_ex)(HANDLE Server, SOCKET so, int type, char *buf, int len, int count);
typedef void(__stdcall *onClient_ex)(HANDLE Client, SOCKET so, int type, char *buf, int len);
extern int g_cpu;
extern int buf_len;
extern HANDLE hEvent_Server;
extern HANDLE hEvent_Client;
extern onServer_ex onServerFunc;
extern onClient_ex onClientFunc;
HANDLE hEvent_Server = NULL;
HANDLE hEvent_Client = NULL;
int g_cpu = 0;
int buf_len = 512;
onServer_ex onServerFunc = NULL;
onClient_ex onClientFunc = NULL;
int closesockets(SOCKET so);
int closesockets(SOCKET so)
{
if (INVALID_SOCKET == so)
{
return 0;
}
struct linger lingerStruct;
lingerStruct.l_onoff = 1;
lingerStruct.l_linger = 0;
setsockopt(so, SOL_SOCKET, SO_LINGER, (char *)&lingerStruct, sizeof(lingerStruct));
shutdown(so, SD_BOTH);
return closesocket(so);
}
bool __stdcall socket_local(char *ip)
{
char hostname[256];
int ret = gethostname(hostname, sizeof(hostname));
if (ret == SOCKET_ERROR)
{
return false;
}
HOSTENT *host = gethostbyname(hostname);
if (host == NULL)
{
return false;
}
strcpy(ip, inet_ntoa(*(in_addr *)*host->h_addr_list));
return true;
}
class Socket_Server_IO;
// 定义一个结构体用于存储服务器信息
typedef struct server_struct
{
OVERLAPPED op; // OVERLAPPED结构用于异步I/O
Socket_Server_IO *so; // 指向服务器对象的指针
int state; // 服务器连接的状态
SOCKET c_socket; // 客户端套接字
char *buf; // 数据缓冲区
DWORD slen; // 接收数据的长度
DWORD cb; // 传输的字节数
DWORD bufSize; // 缓冲区大小
DWORD bufOffset; // 缓冲区的偏移量
} S_server_struct, *P_server_struct; // 定义结构体指针类型
class Socket_Server_IO
{
public:
Socket_Server_IO(void);
~Socket_Server_IO(void);
public:
int Init(char *host, unsigned short nPort, int nIsSC);
int AcceptServer();
int Accept();
void ClientAccept(bool error, P_server_struct op);
void RecvData(bool error, P_server_struct op);
int Close();
int doSend(SOCKET so, char *buf, DWORD cb);
int doSend_sync(SOCKET so, char *buf, DWORD cb);
void OnSend(bool ercode, P_server_struct op);
char *get_ip(SOCKET so)
{
sockaddr_in in;
int len = sizeof(in);
getpeername(so, (sockaddr *)&in, &len);
return inet_ntoa(in.sin_addr);
}
SOCKET get_socket()
{
return m_hSocket;
}
u_short get_port()
{
sockaddr_in in;
int len = sizeof(in);
getsockname(m_hSocket, (sockaddr *)&in, &len);
return ntohs(in.sin_port);
}
char *get_addr(SOCKET m_hSocket)
{
sockaddr_in in;
int len = sizeof(in);
getsockname(m_hSocket, (sockaddr *)&in, &len);
return inet_ntoa(in.sin_addr);
}
public:
SOCKET m_hSocket;
int m_count;
CRITICAL_SECTION m_token;
BOOL m_mate;
BOOL m_stop;
};
Socket_Server_IO::Socket_Server_IO(void)
{
m_stop = FALSE;
InitializeCriticalSection(&m_token);
m_count = 0;
m_hSocket = INVALID_SOCKET;
}
Socket_Server_IO::~Socket_Server_IO(void)
{
m_count = 0;
m_hSocket = INVALID_SOCKET;
}
int Socket_Server_IO::Init(char *host, unsigned short nPort, int nIs)
{
// 设置成员变量m_mate
m_mate = nIs;
// 创建一个重叠模式的套接字
m_hSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == m_hSocket)
{
// 如果创建套接字失败,返回错误码
return WSAGetLastError();
}
// 将套接字关联到一个I/O完成端口
HANDLE t = CreateIoCompletionPort((HANDLE)m_hSocket, hEvent_Server, 0, 0);
if (NULL == t)
{
// 如果关联失败,关闭套接字并返回错误码
Close();
return GetLastError();
}
// 初始化sockaddr_in结构体
sockaddr_in in;
in.sin_family = AF_INET;
in.sin_addr.S_un.S_addr = inet_addr(host); // 设置主机地址
in.sin_port = htons(nPort); // 设置端口号
// 绑定套接字
if (SOCKET_ERROR == bind(m_hSocket, (SOCKADDR *)&in, sizeof(in)))
{
// 如果绑定失败,关闭套接字并返回错误码
Close();
return WSAGetLastError();
}
// 开始监听套接字
if (SOCKET_ERROR == listen(m_hSocket, g_cpu))
{
// 如果监听失败,关闭套接字并返回错误码
Close();
return WSAGetLastError();
}
// 接受客户端连接
return AcceptServer();
}
int Socket_Server_IO::AcceptServer()
{
// 为服务器结构分配内存
server_struct *op = new server_struct;
// 初始化内存
memset(op, 0, sizeof(server_struct));
// 为数据分配缓冲区
op->buf = new char[buf_len];
// 设置服务器对象指针
op->so = this;
// 设置缓冲区大小和偏移量
op->bufSize = buf_len;
op->bufOffset = 0;
// 设置服务器连接的初始状态
op->state = tcp_server_connt;
// 将客户端套接字初始化为无效值
op->c_socket = INVALID_SOCKET;
// 创建一个带有重叠I/O的新的套接字
op->c_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
// 如果套接字创建失败,清理并返回错误代码
if (INVALID_SOCKET == op->c_socket)
{
delete[] op->buf;
op->buf = NULL;
delete op;
op = NULL;
Close();
return WSAGetLastError();
}
// 设置套接字选项
setsockopt(op->c_socket, SOL_SOCKET, SO_RCVBUF, (const char *)&buf_len, sizeof(int)); // 设置接收缓冲区大小
// 设置接收缓冲区大小为 buf_len
int nSendBuf = 0;
setsockopt(op->c_socket, SOL_SOCKET, SO_SNDBUF, (const char *)&nSendBuf, sizeof(int)); // 设置发送缓冲区大小为 0
// 设置发送缓冲区大小为 0
BOOL bReuseaddr = TRUE;
setsockopt(op->c_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&bReuseaddr, sizeof(BOOL)); // 启用地址重用选项
// 启用地址重用选项,允许套接字绑定到已在使用中的地址上
// 创建一个I/O完成端口并将其与套接字关联
HANDLE t = NULL;
t = CreateIoCompletionPort((HANDLE)op->c_socket, hEvent_Server, 0, 0);
// 创建 IO 完成端口,并将 op->c_socket 关联到 hEvent_Server 上进行异步 IO 操作
if (NULL == t)
{
// 如果创建 IO 完成端口失败,则进行以下操作:
closesocket(op->c_socket); // 关闭套接字
op->c_socket = INVALID_SOCKET; // 设置套接字为无效值
delete[] op->buf; // 删除 op 对象中的缓冲区数组
op->buf = NULL; // 将缓冲区指针置空
delete op; // 删除 op 对象
op = NULL; // 将 op 指针置空
Close(); // 调用 Close() 函数(假设该函数用于执行额外的关闭操作)
return GetLastError(); // 返回最后的错误代码
}
// 获取 AcceptEx 函数指针
LPFN_ACCEPTEX lpfnAcceptEx = NULL;
GUID lGUID = WSAID_ACCEPTEX; // 定义 AcceptEx 函数的 GUID
DWORD cb = 0;
// 使用 WSAIoctl 函数获取 AcceptEx 函数指针
if (WSAIoctl(m_hSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &lGUID, sizeof(GUID), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &cb, NULL, NULL))
{
// 如果获取函数指针失败,则进行以下操作:
closesocket(op->c_socket); // 关闭套接字
op->c_socket = INVALID_SOCKET; // 设置套接字为无效值
delete[] op->buf; // 删除 op 对象中的缓冲区数组
op->buf = NULL; // 将缓冲区指针置空
delete op; // 删除 op 对象
op = NULL; // 将 op 指针置空
Close(); // 调用 Close() 函数(假设该函数用于执行额外的关闭操作)
return 2; // 返回错误代码 2(自定义的错误代码,具体含义由上下文决定)
}
// 发出异步 AcceptEx 操作
DWORD Cb = 0;
// 调用 lpfnAcceptEx 函数发起异步 AcceptEx 操作
if (lpfnAcceptEx(m_hSocket, op->c_socket, op->buf, 0, sizeof(sockaddr) + 16, sizeof(sockaddr) + 16, &Cb, (LPOVERLAPPED)op))
{
// 如果 AcceptEx 操作失败,则进行以下操作:
closesocket(op->c_socket); // 关闭套接字
op->c_socket = INVALID_SOCKET; // 设置套接字为无效值
delete[] op->buf; // 删除 op 对象中的缓冲区数组
op->buf = NULL; // 将缓冲区指针置空
delete op; // 删除 op 对象
op = NULL; // 将 op 指针置空
Close(); // 调用 Close() 函数(假设该函数用于执行额外的关闭操作)
return 3; // 返回错误代码 3(自定义的错误代码,具体含义由上下文决定)
}
// 如果一切顺利,返回0
return 0;
}
int Socket_Server_IO::Close()
{
m_stop = TRUE;
m_count = 0;
closesockets(m_hSocket);
m_hSocket = INVALID_SOCKET;
return 0;
}
int Socket_Server_IO::Accept()
{
// 分配并初始化一个 server_struct 结构体
server_struct *op = new server_struct;
memset(op, 0, sizeof(server_struct));
// 分配缓冲区,存储接收的数据
op->buf = new char[buf_len];
op->so = this; // 保存当前 Socket_Server_IO 对象的指针
op->bufSize = buf_len; // 设置缓冲区大小
op->bufOffset = 0; // 初始化缓冲区偏移量为 0
op->state = tcp_server_connt; // 设置初始状态为 tcp_server_connt
// 创建一个重叠模式的客户端套接字
op->c_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
// 如果创建客户端套接字失败,释放资源并返回错误码
if (INVALID_SOCKET == op->c_socket)
{
delete[] op->buf; // 释放缓冲区
op->buf = NULL;
delete op; // 删除结构体
op = NULL;
return WSAGetLastError(); // 返回最后的错误码
}
// 设置套接字选项
setsockopt(op->c_socket, SOL_SOCKET, SO_RCVBUF, (const char *)&buf_len, sizeof(int)); // 设置接收缓冲区大小
int nSendBuf = 0;
setsockopt(op->c_socket, SOL_SOCKET, SO_SNDBUF, (const char *)&nSendBuf, sizeof(int)); // 设置发送缓冲区大小为 0
BOOL bReuseaddr = TRUE;
setsockopt(op->c_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&bReuseaddr, sizeof(BOOL)); // 启用地址重用选项
// 将客户端套接字关联到 I/O 完成端口
HANDLE t = NULL;
t = CreateIoCompletionPort((HANDLE)op->c_socket, hEvent_Server, 0, 0);
if (NULL == t)
{
closesockets(op->c_socket); // 关闭客户端套接字
op->c_socket = INVALID_SOCKET;
PostQueuedCompletionStatus(hEvent_Server, 0, 0, (LPOVERLAPPED)op); // 发送完成状态
delete[] op->buf; // 释放缓冲区
op->buf = NULL;
delete op; // 删除结构体
op = NULL;
return GetLastError(); // 返回最后的错误码
}
// 获取 AcceptEx 函数指针
LPFN_ACCEPTEX lpfnAcceptEx = NULL;
GUID lGUID = WSAID_ACCEPTEX;
DWORD cb = 0;
if (WSAIoctl(m_hSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &lGUID, sizeof(GUID), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &cb, NULL, NULL))
{
closesockets(op->c_socket); // 关闭客户端套接字
op->c_socket = INVALID_SOCKET;
PostQueuedCompletionStatus(hEvent_Server, 0, 0, (LPOVERLAPPED)op); // 发送完成状态
delete[] op->buf; // 释放缓冲区
op->buf = NULL;
delete op; // 删除结构体
op = NULL;
return 2; // 返回错误码 2
}
// 调用 AcceptEx 函数接受客户端连接
DWORD Cb = 0;
if (lpfnAcceptEx(m_hSocket, op->c_socket, op->buf, 0, sizeof(sockaddr) + 16, sizeof(sockaddr) + 16, &Cb, (LPOVERLAPPED)op))
{
closesockets(op->c_socket); // 关闭客户端套接字
op->c_socket = INVALID_SOCKET;
PostQueuedCompletionStatus(hEvent_Server, 0, 0, (LPOVERLAPPED)op); // 发送完成状态
delete[] op->buf; // 释放缓冲区
op->buf = NULL;
delete op; // 删除结构体
op = NULL;
return 3; // 返回错误码 3
}
// 返回 0 表示成功
return 0;
}
void Socket_Server_IO::ClientAccept(bool error, P_server_struct user_op)
{
// 尝试在循环中接受新的客户端连接
while (0 != Accept())
{
Sleep(1); // 等待一段短时间后重试
}
// 设置套接字选项以更新接受上下文
setsockopt(user_op->c_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&m_hSocket, sizeof(SOCKET));
// 配置TCP keepalive设置
DWORD Cb = 0;
tcp_keepalive ka;
ka.onoff = 1; // 启用keepalive
ka.keepalivetime = 1000 * 30; // 30秒keepalive时间
ka.keepaliveinterval = 1000 * 5; // 5秒keepalive间隔
WSAIoctl(user_op->c_socket, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &Cb, NULL, NULL);
// 进入临界区以修改共享资源
EnterCriticalSection(&m_token);
m_count++; // 增加连接的客户端数量
LeaveCriticalSection(&m_token);
// 通知服务器函数新的连接
onServerFunc(this, user_op->c_socket, tcp_server_connt, NULL, 0, m_count);
// 如果在接受过程中出现错误,处理错误
if (error)
{
EnterCriticalSection(&m_token);
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token);
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, NULL, 0, m_count);
// 关闭客户端套接字并清理资源
closesocket(user_op->c_socket);
user_op->c_socket = INVALID_SOCKET;
delete[] user_op->buf;
user_op->buf = NULL;
delete user_op;
user_op = NULL;
return;
}
// 设置状态为接收数据
user_op->state = tcp_server_recv;
WSABUF wsabuf;
if (m_mate)
{
// 如果缓冲区大小已更新
delete[] user_op->buf; // 删除原有的缓冲区
user_op->bufOffset = 0; // 重置缓冲区偏移量
user_op->buf = new char[sizeof(DWORD)]; // 分配新缓冲区,大小为 DWORD 的字节大小
user_op->bufSize = sizeof(DWORD); // 设置缓冲区大小为 DWORD 的字节大小
wsabuf.buf = user_op->buf + user_op->bufOffset; // 设置 WSABUF 结构体的 buf 指针为缓冲区的起始位置
wsabuf.len = user_op->bufSize - user_op->bufOffset; // 设置 WSABUF 结构体的 len 为缓冲区的剩余大小
}
else
{
// 使用现有缓冲区
wsabuf.buf = user_op->buf; // 设置 WSABUF 结构体的 buf 指针为现有缓冲区的起始位置
wsabuf.len = buf_len; // 设置 WSABUF 结构体的 len 为现有缓冲区的长度
}
// 初始化标志和字节计数
DWORD Flg = 0;
Cb = 0;
// 发出异步接收操作
// 使用 WSARecv 函数进行异步接收操作
if (WSARecv(user_op->c_socket, &wsabuf, 1, &Cb, &Flg, (LPWSAOVERLAPPED)user_op, NULL))
{
int ercode = WSAGetLastError(); // 获取错误代码
if (ercode == WSAEFAULT)
{
// 处理特定的错误情况(示例中未详细说明处理内容)
return; // 返回,可能需要根据具体情况进行特定处理
}
else if (ercode != WSA_IO_PENDING)
{
// 处理一般错误情况
EnterCriticalSection(&m_token);
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token);
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, NULL, 0, m_count);
// 关闭客户端套接字并清理资源
closesocket(user_op->c_socket); // 关闭客户端套接字
user_op->c_socket = INVALID_SOCKET; // 将套接字置为无效值
delete[] user_op->buf; // 删除缓冲区
user_op->buf = NULL; // 将缓冲区指针置空
delete user_op; // 删除 user_op 对象
user_op = NULL; // 将 user_op 指针置空
return; // 返回,结束处理
}
}
}
void Socket_Server_IO::RecvData(bool error, P_server_struct user_op)
{
// 处理错误情况
if (error)
{
// 进入临界区,减少连接的客户端数量
EnterCriticalSection(&m_token);
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token); // 离开临界区
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, 0, 0, m_count);
// 清理资源
delete[] user_op->buf; // 释放接收缓冲区
user_op->buf = NULL; // 将缓冲区指针置空
delete user_op; // 释放用户操作结构体对象
user_op = NULL; // 将结构体指针置空
return;
}
// 检查是否启用缓冲区大小处理
if (m_mate)
{
user_op->bufOffset += user_op->cb; // 更新已接收数据的偏移量
// 如果缓冲区尚未完全接收,则继续接收
if (user_op->bufOffset < user_op->bufSize)
{
user_op->state = tcp_server_recv; // 设置状态为接收数据
WSABUF wsabuf;
// 设置 WSABUF 结构
if (m_mate)
{
wsabuf.buf = user_op->buf + user_op->bufOffset; // 设置缓冲区起始位置
wsabuf.len = user_op->bufSize - user_op->bufOffset; // 设置剩余接收长度
}
else
{
wsabuf.buf = user_op->buf; // 设置缓冲区起始位置
wsabuf.len = buf_len; // 设置缓冲区长度
}
DWORD Cb = 0;
DWORD Flg = 0;
// 发出异步接收操作
if (WSARecv(user_op->c_socket, &wsabuf, 1, &Cb, &Flg, (LPWSAOVERLAPPED)user_op, NULL))
{
int ercode = WSAGetLastError();
// 处理特定错误
if (ercode == WSAEFAULT)
{
return; // 如果缓冲区不合法,直接返回
}
else if (ercode != WSA_IO_PENDING)
{
EnterCriticalSection(&m_token); // 进入临界区
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token); // 离开临界区
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, 0, 0, m_count);
// 清理资源
delete[] user_op->buf; // 释放接收缓冲区
user_op->buf = NULL; // 将缓冲区指针置空
delete user_op; // 释放用户操作结构体对象
user_op = NULL; // 将结构体指针置空
return;
}
}
return;
}
// 处理接收到的数据大小
DWORD size = *((DWORD *)(user_op->buf)); // 从缓冲区获取数据大小
if (size > 65536000)
{ // 检查数据大小是否过大
EnterCriticalSection(&m_token); // 进入临界区
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token); // 离开临界区
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, 0, 0, m_count);
// 清理资源
delete[] user_op->buf; // 释放接收缓冲区
user_op->buf = NULL; // 将缓冲区指针置空
delete user_op; // 释放用户操作结构体对象
user_op = NULL; // 将结构体指针置空
return;
}
// 如果缓冲区尚未完全接收,分配新的缓冲区并继续接收
if (user_op->bufOffset < DWORD(sizeof(DWORD)) + size)
{
delete[] user_op->buf; // 释放旧的接收缓冲区
user_op->buf = new char[sizeof(DWORD) + size]; // 分配新的接收缓冲区
user_op->bufSize = sizeof(DWORD) + size; // 设置新缓冲区大小
user_op->bufOffset = sizeof(DWORD); // 设置偏移量从数据大小之后开始
memcpy(user_op->buf, &size, sizeof(DWORD)); // 将数据大小写入缓冲区
user_op->state = tcp_server_recv; // 设置状态为接收数据
WSABUF wsabuf;
// 设置 WSABUF 结构
if (m_mate)
{
wsabuf.buf = user_op->buf + user_op->bufOffset; // 设置缓冲区起始位置
wsabuf.len = user_op->bufSize - user_op->bufOffset; // 设置剩余接收长度
}
else
{
wsabuf.buf = user_op->buf; // 设置缓冲区起始位置
wsabuf.len = buf_len; // 设置缓冲区长度
}
DWORD Cb = 0;
DWORD Flg = 0;
// 发出异步接收操作
if (WSARecv(user_op->c_socket, &wsabuf, 1, &Cb, &Flg, (LPWSAOVERLAPPED)user_op, NULL))
{
int ercode = WSAGetLastError();
// 处理特定错误
if (ercode == WSAEFAULT)
{
return; // 如果缓冲区不合法,直接返回
}
else if (ercode != WSA_IO_PENDING)
{
EnterCriticalSection(&m_token); // 进入临界区
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token); // 离开临界区
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, 0, 0, m_count);
// 清理资源
delete[] user_op->buf; // 释放接收缓冲区
user_op->buf = NULL; // 将缓冲区指针置空
delete user_op; // 释放用户操作结构体对象
user_op = NULL; // 将结构体指针置空
return;
}
}
return;
}
// 如果接收到完整的数据,处理数据
if (user_op->bufSize - sizeof(DWORD) > 0)
{
// 调用处理接收数据的函数
onServerFunc(this, user_op->c_socket, tcp_server_recv, user_op->buf + sizeof(DWORD), user_op->bufSize - sizeof(DWORD), m_count);
}
// 释放接收缓冲区,为下一次接收操作分配新的缓冲区
delete[] user_op->buf;
user_op->buf = new char[sizeof(DWORD)];
user_op->bufSize = sizeof(DWORD);
}
else
{
// 如果未启用缓冲区大小处理,直接处理接收到的数据
onServerFunc(this, user_op->c_socket, tcp_server_recv, user_op->buf, user_op->cb, m_count);
}
// 重置缓冲区偏移量和状态,为下一次接收操作设置 WSABUF 结构
user_op->bufOffset = 0;
user_op->state = tcp_server_recv;
WSABUF wsabuf;
// 设置 WSABUF 结构用于下一次接收操作
if (m_mate)
{
wsabuf.buf = user_op->buf + user_op->bufOffset; // 设置缓冲区起始位置
wsabuf.len = user_op->bufSize - user_op->bufOffset; // 设置剩余接收长度
}
else
{
wsabuf.buf = user_op->buf; // 设置缓冲区起始位置
wsabuf.len = buf_len; // 设置缓冲区长度
}
DWORD Cb = 0;
DWORD Flg = 0;
// 发出异步接收操作
if (WSARecv(user_op->c_socket, &wsabuf, 1, &Cb, &Flg, (LPWSAOVERLAPPED)user_op, NULL))
{
int ercode = WSAGetLastError();
// 处理特定错误
if (ercode == WSAEFAULT)
{
return; // 如果缓冲区不合法,直接返回
}
else if (ercode != WSA_IO_PENDING)
{
EnterCriticalSection(&m_token); // 进入临界区
m_count--; // 减少连接的客户端数量
LeaveCriticalSection(&m_token); // 离开临界区
// 通知服务器函数连接关闭
onServerFunc(this, user_op->c_socket, tcp_server_close, 0, 0, m_count);
// 清理资源
delete[] user_op->buf; // 释放接收缓冲区
user_op->buf = NULL; // 将缓冲区指针置空
delete user_op; // 释放用户操作结构体对象
user_op = NULL; // 将结构体指针置空
}
}
}
int Socket_Server_IO::doSend(SOCKET so, char *buf, DWORD cb)
{
// 检查要发送的数据大小是否超过最大允许大小
if (cb > 65536000)
{
return 0; // 如果超过,返回0表示失败
}
// 分配并初始化一个新的 server_struct 实例用于发送操作
server_struct *op = new server_struct;
memset(op, 0, sizeof(server_struct));
op->so = this; // 将当前 Socket_Server_IO 实例指针赋值给 op 的 so 字段
op->state = tcp_server_send; // 将状态设置为发送
WSABUF wsabuf;
// 检查是否启用了缓冲区大小处理
if (m_mate)
{
// 分配一个新的缓冲区,包括数据大小
op->buf = new char[sizeof(DWORD) + cb];
op->bufSize = sizeof(DWORD) + cb;
wsabuf.buf = op->buf;
wsabuf.len = op->bufSize;
// 将数据大小和实际数据复制到缓冲区中
memcpy(wsabuf.buf, &cb, sizeof(DWORD));
memcpy(wsabuf.buf + sizeof(DWORD), buf, cb);
}
else
{
// 如果未启用缓冲区大小处理,直接使用提供的缓冲区
wsabuf.buf = buf;
wsabuf.len = cb;
}
op->bufOffset = 0; // 初始化缓冲区偏移量
// 发起一个异步发送操作
if (WSASend(so, &wsabuf, 1, &op->cb, 0, (LPWSAOVERLAPPED)op, NULL))
{
int ercode = WSAGetLastError();
// 处理特定错误
if (ercode != WSA_IO_PENDING)
{
// 如果发送操作失败,清理资源
delete[] op->buf;
op->buf = NULL;
delete op;
op = NULL;
return 1; // 返回1表示失败
}
}
return 0; // 返回0表示发送操作成功启动
}
int Socket_Server_IO::doSend_sync(SOCKET so, char *buf, DWORD cb)
{
if (cb > 65536000)
{
return 0;
}
if (m_mate)
{
memcpy(buf, &cb, sizeof(DWORD));
memcpy(buf + sizeof(DWORD), buf, cb);
if (send(so, buf, cb + sizeof(DWORD), 0))
{
return 0;
}
}
else
{
if (send(so, buf, cb, 0))
{
return 0;
}
}
return 1;
}
void Socket_Server_IO::OnSend(bool ercode, P_server_struct user_op)
{
SOCKET n_so = user_op->c_socket;
delete[] user_op->buf;
user_op->buf = NULL;
delete user_op;
user_op = NULL;
if (ercode)
{
closesockets(n_so);
onServerFunc(this, n_so, tcp_server_stop, 0, 0, m_count);
n_so = INVALID_SOCKET;
}
}
class Socket_Client_IO;
typedef struct client_struct
{
OVERLAPPED op; // 用于重叠I/O操作的结构
Socket_Client_IO *so; // 指向Socket_Client_IO实例的指针
int state; // 客户端连接的状态
char *buf; // 数据缓冲区
DWORD slen; // 缓冲区的长度
DWORD cb; // 传输的字节数
DWORD bufSize; // 缓冲区的大小
DWORD bufOffset; // 缓冲区的偏移量
} S_client_struct, *P_client_struct; // 结构体及其指针的类型定义
class Socket_Client_IO
{
public:
Socket_Client_IO(void);
~Socket_Client_IO(void);
int Init(char *host, unsigned short nPort, BOOL nIs, int time);
void OnConnect(bool ercode, P_client_struct op);
void OnClose(bool ercode, P_client_struct op);
void OnRecv(bool ercode, P_client_struct op);
int SoRecv(P_client_struct op);
int Close();
int doSend(char *buf, DWORD cb, int isok, char *outbuf, int outtime);
void OnSend(bool ercode, P_client_struct op);
SOCKET get_socket()
{
return m_hSocket;
}
public:
SOCKET m_hSocket;
BOOL m_mate;
int m_full;
char *m_buf;
};
Socket_Client_IO::Socket_Client_IO(void)
{
m_hSocket = INVALID_SOCKET;
}
Socket_Client_IO::~Socket_Client_IO(void)
{
m_hSocket = INVALID_SOCKET;
}
int Socket_Client_IO::Init(char *host, unsigned short port, BOOL mate, int time)
{
// 为客户端创建一个套接字
m_hSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == m_hSocket)
{
return WSAGetLastError(); // 如果创建套接字失败,返回错误代码
}
// 将套接字与I/O完成端口关联
HANDLE t = CreateIoCompletionPort((HANDLE)m_hSocket, hEvent_Client, 0, 0);
if (NULL == t)
{
Close(); // 如果关联失败,关闭套接字
return GetLastError(); // 返回错误代码
}
// 初始化sockaddr_in结构以绑定套接字
sockaddr_in in;
in.sin_family = AF_INET;
in.sin_addr.S_un.S_addr = 0; // 使用任何可用的本地地址
in.sin_port = 0; // 使用任何可用的端口
// 绑定套接字
if (SOCKET_ERROR == bind(m_hSocket, (SOCKADDR *)&in, sizeof(in)))
{
Close(); // 如果绑定失败,关闭套接字
return WSAGetLastError(); // 返回错误代码
}
m_mate = mate; // 存储mate参数
// 解析主机地址并设置用于连接的sockaddr_in结构
in.sin_family = AF_INET;
struct hostent *pHost;
pHost = gethostbyname(host);
memcpy(&in.sin_addr.S_un.S_addr, pHost->h_addr_list[0], pHost->h_length);
in.sin_addr.S_un.S_addr = inet_addr(inet_ntoa(in.sin_addr));
in.sin_port = htons(port); // 设置端口
// 将套接字设置为非阻塞模式
unsigned long ul = 1;
ioctlsocket(m_hSocket, FIONBIO, (unsigned long *)&ul);
// 发起与服务器的连接
connect(m_hSocket, (sockaddr *)&in, sizeof(sockaddr));
// 设置连接的超时时间
struct timeval timeout;
fd_set r;
FD_ZERO(&r);
FD_SET(m_hSocket, &r);
timeout.tv_sec = time;
timeout.tv_usec = 0;
// 使用select等待连接建立或超时
int ret = select(m_hSocket, 0, &r, 0, &timeout);
if (ret <= 0)
{
Close(); // 如果连接失败或超时,关闭套接字
return 1; // 返回错误代码
}
// 为连接分配并初始化一个client_struct
client_struct *op = new client_struct;
memset(op, 0, sizeof(client_struct));
op->so = this;
op->state = tcp_client_connt; // 设置初始状态
op->buf = NULL;
op->bufSize = 0;
op->bufOffset = 0;
// 将完成状态发布到I/O完成端口
PostQueuedCompletionStatus(hEvent_Client, 0, 0, (LPOVERLAPPED)op);
return 0; // 返回成功
}
void Socket_Client_IO::OnConnect(bool ercode, P_client_struct op)
{
// 设置套接字选项(这里的0x7010是一个自定义选项,具体含义取决于上下文)
setsockopt(m_hSocket, SOL_SOCKET, 0x7010, NULL, 0);
// 调用客户端连接函数,通知连接成功
onClientFunc(this, m_hSocket, tcp_client_connt, NULL, 0);
// 如果有错误码,关闭连接并返回
if (ercode)
{
OnClose(ercode, op);
return;
}
// 删除旧的缓冲区
delete[] op->buf;
// 根据m_mate的值分配新的缓冲区
if (m_mate)
{
// 如果m_mate为true,分配sizeof(DWORD)大小的缓冲区
op->buf = new char[sizeof(DWORD)];
op->bufSize = sizeof(DWORD);
}
else
{
// 如果m_mate为false,分配tcp_len大小的缓冲区
op->buf = new char[tcp_len];
op->bufSize = tcp_len;
}
// 设置状态为接收数据
op->state = tcp_client_recv;
// 将缓冲区偏移量重置为0
op->bufOffset = 0;
// 尝试接收数据,如果接收失败,关闭连接并返回
if (1 == SoRecv(op))
{
OnClose(ercode, op);
return;
}
}
void Socket_Client_IO::OnRecv(bool ercode, P_client_struct op)
{
// 如果发生错误,关闭连接并返回
if (ercode)
{
OnClose(ercode, op);
return;
}
// 如果m_mate为true,进行以下操作
if (m_mate)
{
// 更新缓冲区的偏移量
op->bufOffset += op->cb;
// 如果缓冲区未填满,继续接收数据
if (op->bufOffset < op->bufSize)
{
if (1 == SoRecv(op))
{
OnClose(ercode, op);
return;
}
return;
}
// 获取数据大小
DWORD size = *((DWORD *)(op->buf));
// 如果数据大小超过最大限制,关闭连接
if (size > 65536000)
{
OnClose(ercode, op);
return;
}
// 如果缓冲区未填满,重新分配缓冲区并继续接收数据
if (op->bufOffset < DWORD(sizeof(DWORD)) + size)
{
delete[] op->buf;
op->buf = new char[sizeof(DWORD) + size];
op->bufSize = sizeof(DWORD) + size;
op->bufOffset = sizeof(DWORD);
memcpy(op->buf, &size, sizeof(DWORD));
if (1 == SoRecv(op))
{
OnClose(ercode, op);
return;
}
return;
}
// 如果缓冲区内有数据,并且m_full大于0,复制数据到m_buf并重置m_full
if (op->bufSize - sizeof(DWORD) > 0)
{
if (m_full > 0)
{
memcpy(m_buf, op->buf + sizeof(DWORD), op->bufSize - sizeof(DWORD));
m_full = 0;
}
// 调用客户端接收函数
onClientFunc(this, m_hSocket, tcp_client_recv, op->buf + sizeof(DWORD), op->bufSize - sizeof(DWORD));
}
// 释放当前缓冲区并分配新的缓冲区
delete[] op->buf;
op->buf = new char[sizeof(DWORD)];
op->bufSize = sizeof(DWORD);
}
else
{
// 如果m_mate为false,直接处理接收到的数据
if (m_full > 0)
{
memcpy(m_buf, op->buf, op->cb);
}
// 调用客户端接收函数
onClientFunc(this, m_hSocket, tcp_client_recv, op->buf, op->cb);
m_full = 0;
}
// 重置缓冲区偏移量
op->bufOffset = 0;
// 继续接收数据,如果失败则关闭连接
if (1 == SoRecv(op))
{
OnClose(ercode, op);
return;
}
}
int Socket_Client_IO::SoRecv(P_client_struct op)
{
// 设置当前Socket_Client_IO实例指针
op->so = this;
// 设置状态为接收数据
op->state = tcp_client_recv;
// 设置WSABUF结构,用于接收数据
WSABUF wsabuf;
wsabuf.buf = op->buf + op->bufOffset; // 缓冲区的起始位置
wsabuf.len = op->bufSize - op->bufOffset; // 缓冲区的长度
// 设置标志为0
DWORD Flg = 0;
// 调用WSARecv函数异步接收数据
if (WSARecv(m_hSocket, &wsabuf, 1, &op->cb, &Flg, (LPWSAOVERLAPPED)op, NULL))
{
// 如果WSARecv返回非零值,获取错误码
int ercode = WSAGetLastError();
// 如果错误码是WSAEFAULT,表示缓冲区不正确,返回0表示成功
if (ercode == WSAEFAULT)
{
return 0;
}
// 如果错误码不是WSA_IO_PENDING,表示接收操作没有挂起,返回1表示失败
else if (ercode != WSA_IO_PENDING)
{
return 1;
}
}
// 返回0表示成功
return 0;
}
void Socket_Client_IO::OnClose(bool ercode, P_client_struct op)
{
delete[] op->buf;
op->buf = NULL;
delete op;
op = NULL;
onClientFunc(this, m_hSocket, tcp_client_stop, NULL, 0);
Close();
}
int Socket_Client_IO::Close()
{
closesockets(m_hSocket);
m_hSocket = INVALID_SOCKET;
return 0;
}
int Socket_Client_IO::doSend(char *buf, DWORD cb, int isok, char *outbuf, int outtime)
{
// 检查发送数据大小是否超过限制
if (cb > 65536000)
{
return 0; // 如果超过限制,返回0表示失败
}
// 设置成员变量m_full和m_buf
m_full = isok;
m_buf = outbuf;
// 分配并初始化一个client_struct结构体
client_struct *op = new client_struct;
memset(op, 0, sizeof(client_struct));
op->so = this;
op->state = tcp_client_send;
// 设置WSABUF结构,用于发送数据
WSABUF wsabuf;
// 如果m_mate为true,构造发送缓冲区
if (m_mate)
{
op->buf = new char[sizeof(DWORD) + cb];
op->bufSize = sizeof(DWORD) + cb;
wsabuf.buf = op->buf;
wsabuf.len = op->bufSize;
memcpy(wsabuf.buf, &cb, sizeof(DWORD)); // 复制数据大小
memcpy(wsabuf.buf + sizeof(DWORD), buf, cb); // 复制实际数据
}
else
{
// 如果m_mate为false,直接使用传入的缓冲区
op->buf = buf;
op->bufSize = cb;
wsabuf.buf = op->buf;
wsabuf.len = op->bufSize;
}
// 调用WSASend函数异步发送数据
if (WSASend(m_hSocket, &wsabuf, 1, &op->cb, 0, (LPWSAOVERLAPPED)op, NULL))
{
int ercode = WSAGetLastError();
// 如果错误码不是WSA_IO_PENDING,表示发送操作失败
if (ercode != WSA_IO_PENDING)
{
delete[] op->buf; // 释放缓冲区
delete op; // 删除client_struct结构体
return 1; // 返回1表示失败
}
}
int ni = 0;
// 如果outtime小于等于0,将其设置为2秒
if (outtime <= 0)
{
outtime = 2;
}
// 将outtime转换为毫秒
outtime = outtime * 1000;
// 等待发送完成或超时
while (1 == m_full)
{
ni++;
// 如果等待时间超过指定的超时时间,重置m_full和m_buf并退出循环
if (ni > outtime)
{
m_full = 0;
m_buf = NULL;
break;
}
Sleep(1); // 每次循环等待1毫秒
}
return 0; // 返回0表示成功
}
void Socket_Client_IO::OnSend(bool ercode, P_client_struct op)
{
if (ercode)
{
OnClose(ercode, op);
return;
}
if (m_mate)
{
delete[] op->buf;
delete op;
}
}
unsigned __stdcall Worker_server(void *pParam)
{
while (true)
{
ULONG cb = 0;
ULONG_PTR key = 0;
server_struct *op = nullptr;
bool error = false;
if (!GetQueuedCompletionStatus(hEvent_Server, &cb, &key, (LPOVERLAPPED *)&op, INFINITE))
{
error = true;
}
Socket_Server_IO *so = op->so;
if (op->state == tcp_server_recv && cb <= 0)
{
error = true;
}
op->cb = cb;
if (so->m_stop)
{
so->OnSend(true, op);
continue;
}
switch (op->state)
{
case tcp_server_connt:
so->ClientAccept(error, op);
break;
case tcp_server_recv:
so->RecvData(error, op);
break;
case tcp_server_send:
so->OnSend(error, op);
break;
default:
// Handle unexpected state
break;
}
}
_endthreadex(0);
return 0;
}
// Client worker function
unsigned __stdcall Worker_client(void *pParam)
{
while (true)
{
ULONG cb = 0;
ULONG_PTR key = 0;
client_struct *op = nullptr;
bool error = false;
if (!GetQueuedCompletionStatus(hEvent_Client, &cb, &key, (LPOVERLAPPED *)&op, INFINITE))
{
error = true;
}
Socket_Client_IO *so = op->so;
if (op->state == tcp_client_recv && cb <= 0)
{
error = true;
}
op->cb = cb;
switch (op->state)
{
case tcp_client_connt:
so->OnConnect(error, op);
break;
case tcp_client_recv:
so->OnRecv(error, op);
break;
case tcp_client_send:
so->OnSend(error, op);
break;
default:
// Handle unexpected state
break;
}
}
_endthreadex(0);
return 0;
}
extern "C" __declspec(dllexport) int __stdcall socket_init(onServer_ex nFun, onClient_ex cFun)
{
WSAData wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
return WSAGetLastError();
}
onServerFunc = nFun;
onClientFunc = cFun;
hEvent_Server = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (hEvent_Server == NULL)
{
return GetLastError();
}
hEvent_Client = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (hEvent_Client == NULL)
{
CloseHandle(hEvent_Server);
return GetLastError();
}
SYSTEM_INFO info;
GetSystemInfo(&info);
g_cpu = info.dwNumberOfProcessors + 2;
if (g_cpu < 5)
{
g_cpu = 5;
}
for (int i = 0; i < g_cpu; i++)
{
HANDLE threadHandle = (HANDLE)_beginthreadex(NULL, 0, &Worker_server, NULL, 0, NULL);
if (threadHandle != NULL)
{
CloseHandle(threadHandle);
}
threadHandle = (HANDLE)_beginthreadex(NULL, 0, &Worker_client, NULL, 0, NULL);
if (threadHandle != NULL)
{
CloseHandle(threadHandle);
}
}
return 0;
}
extern "C" __declspec(dllexport) int __stdcall socket_server(char *host, unsigned short nPort, int nIs)
{
Socket_Server_IO *dServer = new Socket_Server_IO;
if (0 != dServer->Init(host, nPort, nIs))
{
delete dServer;
dServer = NULL;
return 0;
}
return 0;
// 编译的时候需要注释上面返回 并且返回真实指针地址
// return (int)dServer;
}
extern "C" __declspec(dllexport) int __stdcall socket_server_send(HANDLE so, SOCKET client_so, char *buf, int len)
{
return ((Socket_Server_IO *)so)->doSend(client_so, buf, len);
}
extern "C" __declspec(dllexport) int __stdcall socket_server_sends(HANDLE so, SOCKET client_so, char *buf, int len)
{
return ((Socket_Server_IO *)so)->doSend_sync(client_so, buf, len);
}
extern "C" __declspec(dllexport) int __stdcall socket_server_get_port(HANDLE so)
{
return ((Socket_Server_IO *)so)->get_port();
}
char *__stdcall socket_server_get_ip(HANDLE so, SOCKET client_so)
{
return ((Socket_Server_IO *)so)->get_ip(client_so);
}
SOCKET __stdcall socket_server_get_socket(HANDLE so)
{
return ((Socket_Server_IO *)so)->get_socket();
}
extern "C" __declspec(dllexport) int __stdcall socket_server_close(SOCKET so)
{
return closesockets(so);
}
extern "C" __declspec(dllexport) int __stdcall socket_server_stop(HANDLE so)
{
if (IsBadReadPtr(so, 4) != 0)
{
return 0;
}
Socket_Server_IO *dServer = ((Socket_Server_IO *)so);
dServer->Close();
delete dServer;
dServer = NULL;
return 0;
}
extern "C" __declspec(dllexport) int __stdcall socket_client(char *host, unsigned short nPort, BOOL nIs, int time)
{
Socket_Client_IO *dClient = new Socket_Client_IO;
if (0 != dClient->Init(host, nPort, nIs, time))
{
delete dClient;
dClient = NULL;
return 0;
}
return 0;
// 编译的时候需要注释上面返回 并且返回真实指针地址
// return (int)dClient;
}
extern "C" __declspec(dllexport) int __stdcall socket_client_send(HANDLE so, char *buf, int len, int isok, char *outbuf, int outtime)
{
return ((Socket_Client_IO *)so)->doSend(buf, len, isok, outbuf, outtime);
}
extern "C" __declspec(dllexport) int __stdcall socket_client_close(HANDLE so)
{
return ((Socket_Client_IO *)so)->Close();
}
extern "C" __declspec(dllexport) int __stdcall socket_client_get(HANDLE so)
{
return ((Socket_Client_IO *)so)->get_socket();
}
void __stdcall ServerCallback(HANDLE Server, SOCKET so, int type, char *buf, int len, int count)
{
if (type == 1)
{
printf("ServerCallback Connect \n");
char sendData[] = "ServerCallback:helloworld";
socket_server_send(Server, so, sendData, strlen(sendData));
}
else if (type == 2)
{
printf("Received data: %.*s\n", len, buf);
}
}
void __stdcall ClientCallback(HANDLE Client, SOCKET so, int type, char *buf, int len)
{
if (type == 1)
{
printf("ClientCallback Connect \n");
char sendData[] = "ClientCallback:helloworld";
socket_client_send(Client, sendData, strlen(sendData), 0, 0, 0);
}
if (type == 2)
{
printf("Received data: %.*s\n", len, buf);
}
}
int __stdcall main()
{
if (socket_init(ServerCallback, ClientCallback) == 0)
{
Socket_Server_IO *s = new Socket_Server_IO;
printf("S %d \n", s->Init((char *)"0.0.0.0", 8800, 0));
Socket_Client_IO *c = new Socket_Client_IO;
printf("C %d \n", c->Init((char *)"127.0.0.1", 8800, 0, 30));
Sleep(1000 * 60 * 60 * 30);
}
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}