#include <winsock2.h>
#include <mswsock.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "vld.h"
#pragma message("automatic link to ws2_32.lib and mswsock.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "mswsock.lib")
#define RETURN_SUCESS (0)
#define RETURN_FAILED (-1)
#define PORT 5150//端口
#define IOCP_THREAD_MAX 16//最大的线程数
#define DATA_BUFSIZE 8192
//区别是何种完成事件
enum
{
IO_EVENT_ACCEPT,
IO_EVENT_WSARECV,
IO_EVENT_WSARECVFROM,
//不支持异步发送
//IO_EVENT_WSASEND,
//IO_EVENT_WSASENDTO
};
typedef struct
{
//OVERLAPPED要放在第一个
OVERLAPPED overlapped;
int io_type;//指示是何种IO操作
}overlapped_wrapper;
typedef struct
{
//OVERLAPPED要放在第一个
OVERLAPPED overlapped;
int io_type;//指示是何种IO操作
char
SOCKET listen_socket;
SOCKET accept_socket;
}acceptex_block;
typedef struct
{
//OVERLAPPED要放在第一个
OVERLAPPED overlapped;
int io_type;//指示是何种IO操作
char
SOCKET socket;
WSABUF wsa_recv_buf;
DWORD
}recv_block;
typedef struct
{
//OVERLAPPED要放在第一个
OVERLAPPED overlapped;
int io_type;//指示是何种IO操作
char
SOCKET socket;
WSABUF wsa_recv_buf;
DWORD
//UDP包的源地址
struct
int
}recvfrom_block;
int
int
int
int
void
void
void
void
void
void
int init(void);
void uninit(void);
DWORD WINAPI worker_thread(LPVOID
void
//完成端口的句柄
HANDLE
//工作线程句柄
HANDLE
//工作线程数量
int
int main(void)
{
/************************************************************************/
/*TCP的例子*/
/************************************************************************/
SOCKADDR_IN internet_address;
SOCKET listen_socket;
acceptex_block* block;
if(RETURN_FAILED == init())
exit_error();
if
exit_error();
internet_address.sin_family = AF_INET;
internet_address.sin_addr.s_addr = htonl(INADDR_ANY);
internet_address.sin_port = htons(PORT);
if (bind(listen_socket, (PSOCKADDR) &internet_address, sizeof(internet_address)) == SOCKET_ERROR)
exit_error();
if
exit_error();
"listening socket %d\n", PORT);
//把监听的SOCKET和完成端口绑定
if(NULL == CreateIoCompletionPort((HANDLE)listen_socket, g_completion_port, (u_long)listen_socket, 0))
exit_error();
sizeof(acceptex_block));
block->listen_socket = listen_socket;
async_AcceptEx(block);
getchar();
closesocket(listen_socket);
getchar();
uninit();
return
/************************************************************************/
/*UDP的例子*/
/************************************************************************/
//SOCKADDR_IN internet_address;
//SOCKET sock;
//recvfrom_block* block = (recvfrom_block*)malloc(sizeof(recvfrom_block));
//if(RETURN_FAILED == init())
// exit_error();
//if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
// exit_error();
//internet_address.sin_family = AF_INET;
//internet_address.sin_addr.s_addr = htonl(INADDR_ANY);
//internet_address.sin_port = htons(PORT);
//if (bind(sock, (PSOCKADDR) &internet_address, sizeof(internet_address)) == SOCKET_ERROR)
// exit_error();
//if(NULL == CreateIoCompletionPort((HANDLE)sock, g_completion_port, (u_long)sock, 0))
// exit_error();
//block->socket = sock;
//async_WSARecvFrom(block);
//getchar();
//closesocket(sock);
//getchar();
//uninit();
//return 0;
}
int init(void)
{
WSADATA wsa_data;
int
#if defined _DEBUG || defined DEBUG
//调试时用一个线程方便
int
#else
int
#endif
if
return
//建立完成端口
if
return
if(threads > IOCP_THREAD_MAX)
threads = IOCP_THREAD_MAX;
for(i = 0; i < threads; i++)
{
//创建工作线程
g_threads[g_threads_number++] = CreateThread(NULL, 0, worker_thread, NULL, 0, 0);
}
return
}
void uninit(void)
{
//自定义的退出协议,三个参数全为0时退出
PostQueuedCompletionStatus(g_completion_port, 0, 0, NULL);
WaitForMultipleObjects(g_threads_number, g_threads, TRUE, INFINITE);
CloseHandle(g_completion_port);
WSACleanup();
}
int
{
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return
}
void
{
int
if
{
exit(RETURN_SUCESS);
}
else
{
"error:%d\n", error);
exit(RETURN_FAILED);
}
}
/*
投递一次AcceptEx请求
返回TRUE,成功
返回FALSE,失败,WSAGetLastError()获取进一步信息
*/
int
{
DWORD
DWORD
//准备投递一个异步接受请求
SOCKET accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(accept_socket == INVALID_SOCKET)
return
block->io_type = IO_EVENT_ACCEPT;
block->accept_socket = accept_socket;
memset(&block->overlapped, 0,
sizeof(block->overlapped));
sizeof(struct
if(!AcceptEx(
block->listen_socket,
accept_socket,
//这个参数会传递给完成端口
//DATA_BUFSIZE - i * 2, //传0进来,接受的连接的时候不接受数据
address_length, address_length,
&bytes_received,
&block->overlapped))
{
if(WSAGetLastError() != ERROR_IO_PENDING)
goto
}
return
fail:
closesocket(accept_socket);
return
}
/*
投递一次WSARecv请求
返回TRUE,表示接受请求投递成功
返回FALSE,表示连接已经断开,WSAGetLastError()获取进一步信息
*/
int
{
int
DWORD
block->io_type = IO_EVENT_WSARECV;
block->bytes_recveived = 0;
block->wsa_recv_buf.len = DATA_BUFSIZE;
block->wsa_recv_buf.buf = block->buffer;
sizeof(block->overlapped));
//投递一次接受请求
ret = WSARecv(block->socket, &block->wsa_recv_buf, 1, &recv_bytes, &flags,
&(block->overlapped), NULL);
if(ret == -1 && WSAGetLastError() != ERROR_IO_PENDING)
{
"WSARecv() error returns %d\n", ret);
on_tcp_close(block);
return
}
else if((ret == 0) || (ret == -1 && WSAGetLastError() == ERROR_IO_PENDING))
{
//waiting... for next turn
}
else
{
//如果直接收到了数据
block->bytes_recveived = ret;
on_recv(block);
//递归
return
}
return
}
/*
投递一次WSARecvFrom请求
返回TRUE,表示接受请求投递成功
返回FALSE,表示接受请求投递失败,WSAGetLastError()获取进一步信息
*/
int
{
int
DWORD
block->io_type = IO_EVENT_WSARECVFROM;
block->bytes_recveived = 0;
block->wsa_recv_buf.len = DATA_BUFSIZE;
block->wsa_recv_buf.buf = block->buffer;
sizeof(block->from_address));
sizeof(block->from_address);
sizeof(block->overlapped));
//投递一次接受请求
ret = WSARecvFrom(block->socket, &block->wsa_recv_buf, 1, &recv_bytes, &flags,
struct
&(block->overlapped), NULL);
if(ret == -1 && WSAGetLastError() != ERROR_IO_PENDING)
{
"WSARecvFrom() error returns %d %d\n", ret, WSAGetLastError());
on_udp_close(block);
return
}
else if((ret == 0) || (ret == -1 && WSAGetLastError() == ERROR_IO_PENDING))
{
//waiting... for next turn
}
else
{
//如果直接收到了数据
block->bytes_recveived = ret;
on_recvfrom(block);
//递归
return
}
return
}
void
{
DWORD
struct
int local_addr_len = sizeof(struct
struct
int remote_addr_len = sizeof(struct
struct
recv_block* r_block;
"on_acceptex %d\n", block->accept_socket);
sizeof(struct
GetAcceptExSockaddrs(
block->buffer,
//DATA_BUFSIZE - i * 2,
i, i,
&p_local_addr,
&local_addr_len,
&p_remote_addr,
&remote_addr_len
);
struct
"\t本地地址%s:%d\n",
inet_ntoa(p_v4_addr->sin_addr), ntohs(p_v4_addr->sin_port));
struct
"\t远程地址%s:%d\n",
inet_ntoa(p_v4_addr->sin_addr), ntohs(p_v4_addr->sin_port));
//准备投递一次WSARecv请求
sizeof(recv_block));
r_block->socket = block->accept_socket;
//绑定
HANDLE)r_block->socket,
g_completion_port, (u_long)r_block->socket, 0);
//投递一次接受请求
async_WSARecv(r_block);
//继续投递AcceptEx请求
async_AcceptEx(block);
}
void
{
"on_recv %d, 收到%d bytes数据\n", block->socket, block->bytes_recveived);
async_WSARecv(block);
}
void
{
"on_recvfrom %d, 收到%d bytes数据, 来自%s:%d\n",
block->socket,
block->bytes_recveived,
inet_ntoa(block->from_address.sin_addr),
ntohs(block->from_address.sin_port));
async_WSARecvFrom(block);
}
void
{
"on_tcp_listen_close %d\n", block->accept_socket);
free(block);
closesocket(block->accept_socket);
}
void
{
"on_tcp_close %d\n", block->socket);
free(block);
closesocket(block->socket);
}
void
{
"on_udp_close %d\n", block->socket);
free(block);
closesocket(block->socket);
}
DWORD WINAPI worker_thread(LPVOID
{
DWORD
overlapped_wrapper* over_type;
BOOL
BOOL
UNREFERENCED_PARAMETER(nothing);
for(;;)
{
SOCKET socket;
//注意第三个参数,他是CreateIoCompletionPort时传入的,直接传入的是一个SOCKET
//注意第四个参数,他可能是一个recv_block或acceptex_block结构的指针
//因为OVERLAPPED是PER_IO_OPERATION_DATA的第一个成员,所以可以安全的进行转换
ret = GetQueuedCompletionStatus(g_completion_port, &bytes,
LPDWORD)&socket, (LPOVERLAPPED *) &over_type, INFINITE);
if(ret == ERROR_SUCCESS)
{
DWORD
if(ERROR_INVALID_HANDLE == last_error)
{
"完成端口被关闭,退出\n");
return
}
else if(ERROR_NETNAME_DELETED == last_error
|| ERROR_OPERATION_ABORTED == last_error)
{
"socket被关闭 或者 操作被取消\n");
close_socket = TRUE;
}
else
{
"GetLastError %d\n", last_error);
continue;
}
}
//自定义的退出协议,三个参数全为0时退出(见uninit中的PostQueuedCompletionStatus)
else if(bytes == 0 && socket == 0 && over_type == NULL)
{
return
}
assert(over_type);
switch(over_type->io_type)
{
case
{
acceptex_block* a_block = (acceptex_block*)over_type;
if(close_socket)
{
on_tcp_listen_close(a_block);
}
else
{
on_acceptex(a_block);
}
}
break;
case
{
recv_block* r_block = (recv_block*)over_type;
//连接断开
if
{
//测试一下,确定对方肯定关闭连接了
char
int r = recv(r_block->socket, &test_close, sizeof(test_close), MSG_PEEK);
if(r == 0 || r == -1)
{
on_tcp_close(r_block);
}
}
//收到了bytes字节的数据
else
{
//处理数据
r_block->bytes_recveived = bytes;
on_recv(r_block);
}
}
break;
case
{
recvfrom_block* rf_block = (recvfrom_block*)over_type;
if(close_socket || bytes == -1 || bytes == 0)
{
on_udp_close(rf_block);
}
else
{
//处理数据
rf_block->bytes_recveived = bytes;
on_recvfrom(rf_block);
}
}
break;
default:
break;
}
}
return
}
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Go程序的交叉编译
Go程序的交叉编译是每一位GO程序猿必须掌握的知识点。但是我没有。在昨天,我编译了一个项目,生成了二进制,放到目标机器上,执行报错,错误如下:bash: ./api.linux: cannot execute binary file: Exec format error提示很明显,可执行文件格式错误,不能执行二进制文件。直接定位到了,是目标机器的内核跟我的Macbook Pro不匹配;接着在目标系
cannot execute binar Exec format error GOARCH GO交叉编译 aarch64 -
IOCP简介客户端 数据 服务器 完成端口 服务端
-
IOCP 模型实现
IOCP模型
iocp 服务器 客户端 数据 -
java网页在线批注excel
1.注解的概念 注解是一个代码级别的说明,一种标识.(标识中可以记录一些信息,作为配置信息) 2.注解的作用: - 编写文档:通过代码里标识的注解生成文档【例如,生成文档doc文档】
java网页在线批注excel java注解 java基础 大数据基础之java注解 System