如果调用它的线程死掉,则取消ReadFile(套接字)

时间:2013-09-01 12:38:37

标签: sockets winapi winsock

我正在尝试学习异步I / O.
我的程序创建套接字,并使用AcceptEx接受它们或使用connect连接它们。在它的主线程中,我在循环中调用WaitForMultipleObjects(),但我仍然创建线程来解析名称,调用connect()并调用初始的ReadFile()。 这些线程在调用ReadFile()并让主线程等待读取结果后退出。

由于某种原因,在连接线程终止后,读取操作被取消,事件被触发并且GetOverlappedResult()因ERROR_OPERATION_ABORTED而失败

示例:

#define _WIN32_WINNT 0x0501

#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include <windows.h>

#include <stdio.h>
#include <tchar.h>


#define BUFSZ 2048

#define PORT 80
#define HOST "192.168.2.1"
#define HOST "stackoverflow.com"

static struct {
    char buf[BUFSZ];
    OVERLAPPED overlap;
    SOCKET sock;
} x = { 0 };

static DWORD WINAPI barthread(LPVOID param) {
    static struct sockaddr_in inaddr = { 0 };
    int rc;
    BOOL b;
    DWORD dw;
    DWORD nb;
    LPHOSTENT lphost;

    x.sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    inaddr.sin_family = AF_INET;

    lphost = gethostbyname(HOST);
    inaddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
    inaddr.sin_port = htons(PORT);

    rc = connect(x.sock, (struct sockaddr *)&inaddr, sizeof(struct sockaddr_in));

    if (rc == 0) {
        printf("thread 2 connected\n");
        printf("thread 2 call ReadFile\n");
        b = ReadFile((HANDLE)x.sock, x.buf, BUFSZ, &nb, &x.overlap);
        dw = GetLastError();
        if (b || dw == ERROR_IO_PENDING) {
            printf("thread 2 ReadFile ok\n");
        } else {
            printf("thread 2 ReadFile failed\n");
        }
        printf("thread 2 sleeping\n");
        Sleep(3000);
        printf("thread 2 dying\n");
    }
    return 0;
}

int main(int argc, char* argv[])
{
    WSADATA WD;

    BOOL b;
    DWORD dw;
    DWORD nb;
    DWORD tid;

    WSAStartup(MAKEWORD(2, 0), &WD);

    x.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    CreateThread(NULL, 0, barthread, NULL, 0, &tid);

    dw = WaitForSingleObject(x.overlap.hEvent, INFINITE);
    printf("thread 1 event triggered\n");
    b = GetOverlappedResult((HANDLE)x.sock, &x.overlap, &nb, FALSE);
    dw = GetLastError();
    printf("thread 1 GetOverlappedResult() = %d, GetLastError() = %d\n", b, dw);

    return 0;
}

2 个答案:

答案 0 :(得分:2)

你根本不应该使用单独的线程。重叠I / O的重点是单个线程可以同时执行多个任务。在阻止模式下,主循环使用WSAAsyncGetHostByName()代替gethostbyname()WSAConnect()使用WSAEventSelect()而非connect()代替{{1}}。

答案 1 :(得分:0)

在这里找到类似的问题: Asynchronous socket reading: the initiating thread must not be exited - what to do?
并且,在这里:http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/asynchronous_operations.html

  

具体而言,在Vista之前的Windows版本中,当启动线程退出时,将取消未完成的操作。

我有Windows 7,但遭遇同样的问题。

不是在临时线程中调用初始的ReadFile(),而是设置一些标志,手动设置事件并在主循环中调用ReadFile()。