Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C windows中相关重叠io的编码模式_C_Windows_Iocp_Overlapped Io - Fatal编程技术网

C windows中相关重叠io的编码模式

C windows中相关重叠io的编码模式,c,windows,iocp,overlapped-io,C,Windows,Iocp,Overlapped Io,我是一名linux程序员,最近参与了将带有两个用c编写的文件描述符的基于epoll的客户端移植到windows。 正如您所知,在使用epoll或select的linux中(我知道windows支持select,但它一点也不高效),您可以在文件描述符出现之前阻止文件描述符 已准备好,您可以知道何时准备好写入和何时读取。 我看了一下windows IOCP,在microsoft world中,对于重叠io来说,这听起来还不错。 但在所有示例中,多客户端服务器都使用每个客户端的套接字独立于其他套接字。

我是一名linux程序员,最近参与了将带有两个用c编写的文件描述符的基于epoll的客户端移植到windows。
正如您所知,在使用epoll或select的linux中(我知道windows支持select,但它一点也不高效),您可以在文件描述符出现之前阻止文件描述符 已准备好,您可以知道何时准备好写入和何时读取。

我看了一下windows IOCP,在microsoft world中,对于重叠io来说,这听起来还不错。 但在所有示例中,多客户端服务器都使用每个客户端的套接字独立于其他套接字。

通过使用completions端口,可以为每个客户机创建completionKey结构,并在struct中放入一个变量,并在调用时将其读取 WSArecv和wirt,当WSAsend和其他变量指示套接字值并从GetQueuedCompletionStatus检索它们以了解该做什么时,如果已对套接字执行写入操作,则执行读取操作,反之亦然。

但在我的例子中,文件描述符(fd)实际上是重叠的。从一个fd读取,会导致对另一个fd的读写,这使得很难知道是什么 GetQueuedCompletionStatus结果中的每个fd都会发生操作,因为每个fd都有一个关联的completionKey。请清楚地考虑一下:

有两个句柄称为fd1和fd2,completionKey1为f1保存句柄和状态,completionKey2为fd2保存句柄和状态,completionKey变量为f1保存状态 正在从GetQueuedCompletionStatus检索完成。

    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;
    }
在上面的代码中,出现了一种情况,即某些修改的CompletionKey将覆盖挂起的读或写操作以及结果 completionKey->status将出错(例如,它将报告读取而不是写入),最糟糕的是缓冲区将覆盖。如果我使用锁定 completionKeys,这将导致死锁情况。

查看WSAsend或WSArecv后,注意到可以为每个发送或接收设置重叠参数。 但这会导致两大问题。根据WSA重叠结构:

    typedef struct _WSAOVERLAPPED {
  ULONG_PTR Internal;
  ULONG_PTR InternalHigh;
  union {
    struct {
      DWORD Offset;
      DWORD OffsetHigh;
    };
    PVOID  Pointer;
  };
  HANDLE    hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;
typedef struct _MyOverlapped
{
  WSAOVERLAPPED overlapped;
  ... your data goes here ...
} MyOverlapped, lpMyOverlapped;
首先,它没有放置状态和适当缓冲区的位置,并且大多数都是保留的。

第二,如果可以解决第一个问题,我需要检查是否没有可用的重叠剩余,并且所有重叠都用于挂起的操作, 为每次读写分配一个新的池,因为客户端将非常繁忙,这可能会发生很多事情,而且,管理那些重叠池是一件令人头痛的事情。 那么,我是遗漏了什么还是微软搞砸了这件事?

因为我不需要多线程,有没有其他方法可以解决我的问题?
提前谢谢
编辑
正如我所猜测的,我在使用重叠结构中提到的第一个问题已经有了答案,我只需要创建另一个包含所有缓冲区和状态等的结构,并将重叠作为第一个字段。
现在你帮我解决其他问题;)

你在问两个不同的问题。我无法回答第一个问题,因为我从未使用过IO完成端口,但从我所读到的所有内容来看,除了专家之外,其他人都最好避免使用这些端口。(我将为您描述的问题指出一个显而易见的解决方案:与其在另一个写操作仍在等待时将数据写入另一个套接字,不如将数据放入队列中,稍后再写入。您仍然需要在给定套接字上同时处理两个操作—一个读操作和一个写操作—但这不应该是一个专业的做法。)问题。)

但是,使用
OVERLAPPED
(或
wsaooverlapped
)结构很容易跟踪重叠请求的状态。您只需将重叠的
结构作为第一个元素嵌入到更大的结构中:

    typedef struct _WSAOVERLAPPED {
  ULONG_PTR Internal;
  ULONG_PTR InternalHigh;
  union {
    struct {
      DWORD Offset;
      DWORD OffsetHigh;
    };
    PVOID  Pointer;
  };
  HANDLE    hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;
typedef struct _MyOverlapped
{
  WSAOVERLAPPED overlapped;
  ... your data goes here ...
} MyOverlapped, lpMyOverlapped;
然后将发送到完成例程的
LPWSAOVERLAPPED
强制转换为
lpMyOverlapped
,以访问上下文数据

或者,如果您使用的是完成例程,
wsaooverlapped
hEvent
成员保证未使用,因此您可以将其设置为指向所选结构的指针


我不明白你为什么认为管理重叠结构池会成为一个问题。每个活动缓冲区只有一个重叠结构,因此每次分配缓冲区时,都要分配相应的重叠结构。

出于好奇,您如何处理Linux端的相应问题?也就是说,当您读取套接字a上的请求并(因此)想写入套接字B,但套接字B还没有准备好写入时?实际上,我有一个队列,我只是向队列写入,并尝试随时退出队列并写入。好吧,那么,每个套接字只需要两个重叠的结构?一个用于一个挂起的读取操作,一个用于一个挂起的写入操作?我试着在你的答案下解释。在我看来,光靠排队是做不到的。而排队正好可以写。对于读取,我需要盲目地使开关块读取,并且需要GetQueuedCompletionStatus不是无限的。考虑到这一点,所有这两个重叠的结构可能会在SokKeTon上等待,更主观的注意:在任何情况下,您可能需要考虑使用队列。我不确定能否保证套接字提供程序能够处理同一套接字上无限数量的挂起异步请求。此外,如果连接断开或发生其他错误,如果您只返回一个错误,而不是每次挂起的写入都返回一个单独的错误,可能会使事情变得更容易。队列应该易于实现;当给定的写入请求完成时,处理队列中的下一项。谢谢harry。关于如何创建适当的重叠结构,您是对的。在上面的伪代码中,当读取完成时,我将缓冲区写入队列。关键是在iocp中,您只需读或写