我是Linux程序员,最近参与了基于epoll的客户端,其中两个文件描述符在c上写给Windows。
如您所知,在Linux中使用Epoll或Select(我知道Windows支持SELECT,但根本不有效)您可以在文件描述符上阻止文件描述符已经准备好了,您可以知道何时准备编写和阅读。
我已经看了Windows IOCP,在Microsoft World中重叠的IO听起来不错。但是在所有样本中,每个客户端的套接字都独立于其他插座。
使用完成端口,可以为每个客户端创建一个完整的结构,然后在struct中放置一个变量,并在调用时读取它WSARECV和WIRT当WSASEND和其他变量指示插座值并从GetQuequeuedCompletionStatus中检索它们,以了解该怎么做,如果为插座完成写作,请阅读,反之亦然。
但就我而言,文件描述符(FD)确实重叠。从一个fd读取,使读写给其他FD,这很难知道什么在GetQueuedCompletionStatus结果中,每个FD的操作都会发生,因为每个FD都有一个完整的关键。要明确考虑一下:
GetQueuedCompletionStatus(port_handle, &completionKey.bufflen, (PULONG_PTR)&completionKey,(LPOVERLAPPED *)&ovl,INFINITE);
switch (completionKey.status)
{
case READ:
if(completionKey->handle == fd1)
{
fd1_read_is_done(completionKey.buffer,completionKey.bufflen);
completionKey->status = WRITE;
do_fd1_write(completionKey);
completionKey2->status = WRITE;
completionKey2->buffer = "somedata";
do_fd2_write(completionKey2);
}
else if(completionKey->handle == fd2)
{
fd2_read_is_done(completionKey.buffer,completionKey.bufflen);
completionKey->status = WRITE;
do_fd2_write(completionKey);
completionKey1->status = WRITE;
completionKey1->buffer = "somedata";
do_fd1_write(completionKey1);
}
break;
case WRITE_EVENT:
if(completionKey->handle == fd1)
{
fd1_write_is_done(completionKey.bufflen);
completionKey->status = READ;
do_fd1_read(completionKey);
completionKey2->status = READ;
do_fd2_read(completionKey2);
}
else if(completionKey->handle == fd2)
{
fd2_write_is_done(completionKey.bufflen);
completionKey->status = READ;
do_fd2_read(completionKey);
completionKey1->status = READ;
do_fd1_read(completionKey1);
}
break;
}
在上面的代码中,某些更改的完成键将覆盖未决的读取或写入,结果完整键 ->状态是错误的(例如,它将报告读取而不是写入),最坏的是缓冲区将覆盖。如果我使用锁定完成键,它将导致死锁状况。
查找WSASEND或WSARECV后,注意到每个发送或接收都可以设置一个重叠参数。但这导致了两个主要问题。根据WSAOVERPLAPED结构:
typedef struct _WSAOVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;
首先,没有位置可以放置状态和适当的缓冲区,其中大多数都保留了。
第二,如果可以解决第一个问题,我需要检查是否没有可用的重叠,并且所有这些都用于待处理操作,为每个读写分配一个新的,并且由于客户会非常忙,因此可能会发生很多事情,此外,管理那些重叠的池是令人头疼的。所以我是缺少某些东西还是微软搞砸了?
由于我不需要多线程,还有另一种方法可以解决我的问题吗?
预先感谢
编辑
正如我猜想的那样,我在使用重叠结构时提到的第一个问题具有答案,我只需要创建另一个带有所有缓冲区和状态以及等等的结构,然后在首次提交时放置重叠。现在您解决了其他人;)
您确实在这里问两个不同的问题。我无法回答第一个,因为我从未使用过IO完成端口,但是从我阅读的所有内容中,除了专家以外,所有人都避免了它们。(我将指出一个明显的解决方案i think 您正在描述:而不是实际将数据写入另一个插座,而另一个写入仍在等待,而是将数据放在队列中并写入稍后。您仍然必须在给定的套接字上处理两个同时操作 - 一个读取和一个写入 - 但这不应该是问题。)
但是,使用OVERLAPPED
(或WSAOVERLAPPED
)结构很容易跟踪重叠请求的状态。您要做的就是将OVERLAPPED
结构嵌入较大结构中的第一个元素:
typedef struct _MyOverlapped
{
WSAOVERLAPPED overlapped;
... your data goes here ...
} MyOverlapped, lpMyOverlapped;
然后将LPWSAOVERLAPPED
施放到lpMyOverlapped
的完成例程以访问您的上下文数据。
另外,如果您使用的是完成例程,则保证hEvent
的CC_6成员未使用,因此您可以将其设置为您选择的结构的指针。
我不明白为什么您认为管理重叠结构的池将是一个问题。每个活动缓冲区都有一个重叠的结构,因此每次分配缓冲区时,都会分配相应的重叠结构。