簡體   English   中英

Windows中相關的重疊io的編碼模式

[英]Coding pattern for dependant overlapped io in windows

我是一名Linux程序員,最近參與了將帶有兩個用c編寫的文件描述符的epoll客戶端移植到Windows的工作。
如您所知,在Linux中使用epoll或select(我知道Windows支持select,但根本沒有效率),您可以阻止文件描述符,直到文件描述符准備就緒,並且可以知道何時可以寫入和讀取。

我看過Windows IOCP,對於Microsoft世界中重疊的io來說還可以。 但是在所有示例中,它都用於多客戶端服務器,每個客戶端的套接字都獨立於其他套接字。

使用完成端口,可以為每個客戶端創建一個完成密鑰結構,並將一個變量放入struct中,並在調用WSArecv時讀取它,並在WSAsend和另一個指示套接字值的變量從wirt讀取,並從GetQueuedCompletionStatus檢索它們以了解操作時,如果對套接字完成了寫入操作,請進行讀取,反之亦然。

但就我而言,文件描述符(fd)實際上是重疊的。 從一個fd讀取數據會導致對另一個fd的讀取和寫入,這使得很難知道GetQueuedCompletionStatus結果中的每個fd實際發生了什么操作,因為每個fd都有一個完成密鑰。 為了清楚起見,請考慮以下事項:

有兩個稱為fd1和fd2的句柄,completionKey1持有f1的句柄和狀態,以及fd2的completedKey2,completionKey變量用於從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后,注意到可以為每個發送或接收設置一個重疊參數。 但它導致兩個主要問題。 根據WSAOVERLAPPED結構:

    typedef struct _WSAOVERLAPPED {
  ULONG_PTR Internal;
  ULONG_PTR InternalHigh;
  union {
    struct {
      DWORD Offset;
      DWORD OffsetHigh;
    };
    PVOID  Pointer;
  };
  HANDLE    hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;

首先,沒有位置可以放置狀態和適當的緩沖區,並且大多數保留。

其次,如果可以解決第一個問題,那么我需要檢查是否沒有可用的重疊部分,並且所有這些重疊部分都用於掛起的操作中,為每次讀寫分配一個新的重疊對象,並且由於客戶端的原因忙,這可能會發生很多,此外,管理那些重疊的池是一件令人頭疼的事情。 所以我錯過了什么還是微軟搞砸了嗎?

而且由於我不需要多線程,還有其他方法可以解決我的問題嗎?
提前致謝
編輯
正如我猜到的那樣,我在使用重疊結構時提到的第一個問題已經解決,我只需要創建另一個具有所有緩沖區和狀態等的結構,然后將OVERLAPPED放在第一個文件中即可。 現在你解決了我其他人;)

您實際上是在問兩個不同的問題。 我無法回答第一個問題,因為我從未使用過IO完成端口,但是從我讀過的所有內容來看,除專家外,最好避免使用它們。 (我將為您認為正在描述的問題指出一個顯而易見的解決方案:與其將數據實際寫入另一個套接字,而不是在另一個寫入仍處於掛起狀態,而是將數據放入隊列中,然后再寫入。您仍然必須在給定的套接字上處理兩個同時的操作-一個讀和一個寫-但這不應該是一個問題。)

但是,使用OVERLAPPED (或WSAOVERLAPPED )結構來跟蹤重疊請求的狀態很容易。 您要做的只是將OVERLAPPED結構嵌入為較大結構中的第一個元素:

typedef struct _MyOverlapped
{
  WSAOVERLAPPED overlapped;
  ... your data goes here ...
} MyOverlapped, lpMyOverlapped;

再鑄造LPWSAOVERLAPPED發送到完成例程lpMyOverlapped訪問您的上下文數據。

或者,如果使用的是完成例程,則確保WSAOVERLAPPEDhEvent成員未使用,因此可以將其設置為指向您選擇的結構的指針。

我不明白為什么您會認為管理重疊結構池會成為問題。 每個活動緩沖區中只有一個重疊結構,因此,每次分配緩沖區時,都要分配一個對應的重疊結構。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM