- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
到目前为止,我发现的所有示例要么只能读取或写入,要么是 10000 行的巨兽,我什至不知道从哪里开始了解它们的工作原理。
为了测试我的代码,我将浏览器指向我的服务器并发送了一个简单的 http 请求。结果令人困惑。
例如,有一次 GetQueuedCompletionStatus 返回并且 WSARecv 说它读取了我发送的 http 响应的字节数,尽管这个响应应该(并且确实)在客户端结束并且 recvbuffer 甚至没有填充这些字节。
此外,我不明白在其他浏览器关闭连接后何时释放我的缓冲区,因为 GetQueuedCompletionStatus 在我调用 closesocket 后不断返回几次。
此外,一旦 GetQueuedCompletionStatus 返回,我不知道何时有数据要读取或有数据要写入。我可以尝试两者,看看哪个失败了,但这似乎很粗鲁。
为了揭露我对 IOCP 可能存在的任何误解,我编写了一些伪代码来表达我认为我的代码所做的事情:
main {
create server socket
create io completion port
while true {
accept client socket
create completion port for client socket
create recv buffer and send buffer for client
call WSARecv once with 0 bytes for whatever reason
}
}
worker thread {
while true {
wait until GetQueuedCompletionStatus returns
do something if that failed, not quite sure what (free buffers?)
if no bytes were transferred, close socket
try to recv data
try to send data
}
}
实际代码:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#define BUFFER_SIZE 1024
typedef struct {
WSAOVERLAPPED overlapped;
SOCKET socket;
WSABUF sendbuf;
WSABUF recvbuf;
char sendbuffer[BUFFER_SIZE];
char recvbuffer[BUFFER_SIZE];
} client;
DWORD WINAPI worker_thread(HANDLE iocp){
DWORD flags = 0, n = 0;
ULONG unused;
client *c;
while (1){
int ret = GetQueuedCompletionStatus(iocp, &n, &unused, (LPOVERLAPPED*)&c, INFINITE);
printf("%3d triggered\n", c->socket);
if (ret == FALSE){
printf("%3d GetQueuedCompletionStatus error %i\n", c->socket, WSAGetLastError());
continue;
}
if (c->socket == INVALID_SOCKET){
printf("error: socket already closed\n");
continue;
}
if (n == 0) {
printf("%3d disconnected\n", c->socket);
closesocket(c->socket);
c->socket = INVALID_SOCKET;
continue;
}
/* how do I know if there is data to read or data to write? */
WSARecv(c->socket, &(c->recvbuf), 1, &n, &flags, &(c->overlapped), NULL);
printf("%3d WSARecv %ld bytes\n", c->socket, n);
WSASend(c->socket, &(c->sendbuf), 1, &n, flags, &(c->overlapped), NULL);
printf("%3d WSASend %ld bytes\n", c->socket, n);
/* TODO handle partial sends */
c->sendbuf.len = 0;
}
return 0;
}
SOCKET make_server(int port){
int yes = 1;
struct sockaddr_in addr;
SOCKET sock;
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
sock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)yes, sizeof(yes));
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
listen(sock, SOMAXCONN);
return sock;
}
int main(){
const char *text =
"HTTP/1.0 200 OK\r\n"
"Content-Length: 13\r\n"
"Content-Type: text/html\r\n"
"Connection: Close\r\n"
"\r\n"
"Hello, World!";
SOCKET server_socket = make_server(8080);
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
CreateThread(NULL, 0, worker_thread, iocp, 0, NULL);
while (1){
DWORD flags = 0, n = 0;
client *c;
struct sockaddr_in addr;
int addrlen = sizeof(addr);
SOCKET client_socket = WSAAccept(server_socket, (struct sockaddr*)&addr, &addrlen, NULL, 0);
printf("%3d connected\n", client_socket);
CreateIoCompletionPort((HANDLE)client_socket, iocp, 0, 0);
c = (client*)calloc(1, sizeof(*c));
c->socket = client_socket;
c->sendbuf.len = strlen(text);
c->recvbuf.len = BUFFER_SIZE;
c->sendbuf.buf = c->sendbuffer;
c->recvbuf.buf = c->recvbuffer;
strcpy(c->sendbuf.buf, text);
/* for some reason I have to receive 0 bytes once */
WSARecv(c->socket, &(c->recvbuf), 1, &n, &flags, &(c->overlapped), NULL);
}
}
示例输出:
/* Browser makes two tcp connections on socket 124 and 128. */
124 connected
128 connected
/* GetQueuedCompletionStatus returned for socket 124. */
124 triggered
/* We received the browser's http request. */
124 WSARecv 375 bytes
/* Send http response to browser. */
124 WSASend 96 bytes
/* GetQueuedCompletionStatus returned again. */
124 triggered
/* This is wrong, we should not receive our response to the browser. */
/* Also we didn't even receive data here. */
/* recvbuffer still contains the http request. */
124 WSARecv 96 bytes
/* this is ok */
124 WSASend 0 bytes
124 triggered
124 disconnected
/* Why does GetQueuedCompletionStatus still return? the socket is closed! */
/* Also how can I tell when I can safely free the buffers */
/* if GetQueuedCompletionStatus keeps returning? */
-1 triggered
-1 GetQueuedCompletionStatus error 1236
-1 triggered
-1 GetQueuedCompletionStatus error 1236
/* same again for second http request */
128 triggered
128 WSARecv 375 bytes
128 WSASend 96 bytes
128 triggered
128 WSARecv 96 bytes
128 WSASend 0 bytes
128 triggered
128 disconnected
-1 triggered
-1 GetQueuedCompletionStatus error 1236
-1 triggered
-1 GetQueuedCompletionStatus error 1236
128 connected
128 triggered
128 WSARecv 375 bytes
128 WSASend 96 bytes
128 triggered
128 WSARecv 96 bytes
128 WSASend 0 bytes
128 triggered
128 disconnected
-1 triggered
-1 GetQueuedCompletionStatus error 1236
-1 triggered
-1 GetQueuedCompletionStatus error 1236
128 connected
128 triggered
128 WSARecv 289 bytes
128 WSASend 96 bytes
128 triggered
128 WSARecv 96 bytes
128 WSASend 0 bytes
128 triggered
128 disconnected
-1 triggered
-1 GetQueuedCompletionStatus error 1236
-1 triggered
-1 GetQueuedCompletionStatus error 1236
最佳答案
您的伪代码工作流应该看起来更像这样:
main {
create server socket
create io completion port
create worker thread
while not done {
accept client socket
associate client socket with completion port
create recv, send, and work buffers for client
call WSARecv with >0 bytes to start filling recv buffer
if failed {
close client socket and free associated buffers
}
}
terminate worker thread
close client sockets
close server socket
}
worker thread {
while not terminated {
call GetQueuedCompletionStatus
if failed {
if failed because of IO error {
close socket and free associated buffers
}
else if not timeout {
handle error as needed
}
}
else if no bytes were transferred {
close socket and free associated buffers
}
else if IO was WSARecv {
move data from recv buffer to end of work buffer
while work buffer has a complete message {
remove message from front of work buffer, process as needed
if output to send {
if send buffer not empty {
append output to end of send buffer, will send later
}
else {
move output to send buffer
call WSASend
if failed {
close socket and free associated buffers
}
}
}
}
call WSARecv with >0 bytes to start filling recv buffer
if failed {
close socket and free associated buffers
}
}
else if IO was WSASend {
remove reported number of bytes from front of send buffer
if send buffer not empty {
call WSASend
if failed {
close socket and free associated buffers
}
}
}
}
}
我会把它留作练习,让您将其转化为您的代码。
关于windows - IOCP 接收和发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25413499/
我正在设计客户端-服务器应用程序。我的服务器将使用 C++ 并使用 IOCP 进行 TCP/IP 通信。 尚未决定用于客户端开发的技术。所以我对 IOCP 与将来要开发的客户端的兼容性有几个问题(我需
我有经典的 IOCP 回调,它以这种方式使 i/o 挂起的请求出列、处理它们并释放它们: struct MyIoRequest { OVERLAPPED o; /* ... other params
我有 IOCP 应用程序,每个套接字上下文存储 64kb 缓冲区。它使用大量 RAM,同时处理数千个套接字。相反,我想切换到每个 iocp 线程上下文有 64kb 缓冲区的模型(就像我可以在 epol
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
正在学习IOCP,根据这个article : To begin using completion ports we need to create a Completion Port which in
我一直在脑海中传递一些关于如何在保持 KISS 的同时使用 IO 类型的架构实际包含大量连接的想法。通过网络上的示例,似乎大多数人都使用带有 CONTAINING_RECORD 的双/单链表。而且,作
我想了解为什么使用 IOCP。我可以想到两个原因: 因为 WSARecv() 不会阻塞,所以我可以处理 1000 个客户端,而不必为每个客户端创建一个新线程(另外,您可以创建的线程数量是有限制的,因此
我最近在 windows 平台上遇到了一个叫做 IOCP 的东西,更准确地说:输入/输出控制端口。这似乎是最有效的编写服务器软件代码的方式,因为它需要同时容纳数千名用户。(如果我错了请纠正我,但是每个
到目前为止,我发现的所有示例要么只能读取或写入,要么是 10000 行的巨兽,我什至不知道从哪里开始了解它们的工作原理。 为了测试我的代码,我将浏览器指向我的服务器并发送了一个简单的 http 请求。
我应该读取前 9 个字节,其中应包括数据包的协议(protocol)和传入大小。 当完成端口返回 9 个字节时哪个更好? (性能/良好实践或美学方面) 在套接字上发送另一个重叠读取,这次使用数据包的大
据我了解Windows Server 2003/2008和C++编程下的IOCP,它们或多或少是服务多个套接字(而不是选择)或将多个线程 bundle 在一起以服务那些请求的最高性能方式。 但是,如果
我正在构建 IOCP/RIO Winsock 服务器,并且当客户端触发我的 AcceptEx() 调用时,一直在努力从完成端口获取正确的通知要求。 当我在发送客户端请求后调用 GetQueuedCom
因此,我构建了一个高度多线程的并发应用程序,它管理自己的工作线程(因为它们在整个应用程序生命周期内运行)。现在我使用 SocketAsyncEventArgs 进行网络连接,它在后台使用 I/O 完成
当我调用 BeginExecuteReader (SQL) 时,它是否使用 IO 完成端口?是什么让它成为异步的?我应该从 Begin[Operation]() 还是从 IAsyncResult 构造
这是Microsoft Windows 网络编程 的代码片段: ... // Determine how many processors are on the system. GetSystemInf
如果 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 未启用,那么即使操作立即成功完成,我仍然会在完成端口上收到完成通知。我想知道如果它也立即完成并出现错误,是否属于这种情况
我正在创建一个客户端程序,它与通过 LAN 连接到我的 PC 的设备进行通信。 我的程序和设备之间典型的通信如下: Program -> Device 1616000D 08 02 00 00
我读到传递给 CreateIoCompletionPort() 函数的 NumberOfConcurrentThreads 参数的理想数字是 0,它将转换为核心数。 但是,我实际应该创建多少个等待完成
我正在为从桌面客户端到浏览器的视频流编写 IOCP 服务器。双方都使用 WebSocket 协议(protocol)来统一服务器的架构(并且因为浏览器没有其他方式可以执行全双工交换)。 工作线程是这样
我可以找到大量关于启动 IOCP 服务器的文章,但没有一篇是关于正确关闭它的 =/ 完成后关闭服务器的正确方法是什么?更具体地说,我已经使用 PostQueuedCompletionStatus()
我是一名优秀的程序员,十分优秀!