C-窗口中依赖重叠的IO的编码模式



我是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中检索完成。
    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成员未使用,因此您可以将其设置为您选择的结构的指针。

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

相关内容

  • 没有找到相关文章