0

我开始开发我的工具,它在 TCP 级别与 net 一起工作,但遇到了以下问题:

  • 为 Winsock的accept()函数创建线程

我已经用谷歌搜索并寻找参考资料,并且到处都有关于创建新线程的信息:

  • 它必须在前缀中有 DWORD WINAPI (unsigned long __stdcall)
  • 它必须接受 LPVOID 参数

并且这样的函数将用作 CreateThread() 函数中的第三个参数作为 LPTHREAD_START_ROUTINE 结构。

但是编译后我得到了下一个错误:

(131):错误 C2664:“CreateThread”:无法将参数 3 从“DWORD (__stdcall Net::*)(LPVOID)”转换为“LPTHREAD_START_ROUTINE”

这是我的代码:

#include <iostream>
#include <Windows.h>

#pragma comment(lib, "Ws2_32.lib")

typedef struct Header
{
friend struct Net;

private:
    WORD wsa_version;
    WSAData wsa_data;

    SOCKET sock;
    SOCKADDR_IN service;

    char *ip;
    unsigned short port;

public:
    Header(void)
    {
        wsa_version = 0x202;

        ip = "0x7f.0.0.1";
        port = 0x51;

        service.sin_family = AF_INET;
        service.sin_addr.s_addr = inet_addr(ip);
        service.sin_port = htons(port);
    }

} Header;

typedef struct Net
{
private:
    int result;

    void WSAInit(WSAData *data, WORD *wsa_version)
    {
        result = WSAStartup(*wsa_version, &(*data));

        if(result != NO_ERROR)
        {
            std::cout << "WSAStartup() failed with the error: " << result << std::endl;
        }
        else
        {
            std::cout << (*data).szDescription << " " << (*data).szSystemStatus << std::endl;
        }
    }

    void SocketInit(SOCKET *my_socket)
    {
        (*my_socket) = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        if((*my_socket) == INVALID_SOCKET)
        {
            std::cout << "Socket initialization failed with the error: " << WSAGetLastError() << std::endl;
            WSACleanup();
        }
        else
        {
            std::cout << "Socket initialization successful!" << std::endl;
        }
    }

    void SocketBind(SOCKET *my_socket, SOCKADDR_IN *service)
    {
        result = bind((*my_socket), (SOCKADDR*)&(*service), sizeof(*service));

        if(result == SOCKET_ERROR)
        {
            std::cout << "Socket binding failed with the error: " << WSAGetLastError() << std::endl;
            closesocket((*my_socket));
            WSACleanup();
        }
        else
        {
            std::cout << "Socket binding successful!" << std::endl;
        }

        result = listen(*my_socket, SOMAXCONN);

        if(result == SOCKET_ERROR)
        {
            std::cout << "Socket listening failed with the error: " << WSAGetLastError() << std::endl;
        }
        else
        {
            std::cout << "Listening to the socket..." << std::endl;
        }
    }

    void SocketAccept(SOCKET *my_socket)
    {
        SOCKET sock_accept = accept((*my_socket), 0, 0);

        if(sock_accept == INVALID_SOCKET)
        {
            std::cout << "Accept failed with the error: " << WSAGetLastError() << std::endl;
            closesocket(*my_socket);
            WSACleanup();
        }
        else
        {
            std::cout << "Client socket connected!" << std::endl;
        }

        char data[0x400];
        result = recv(sock_accept, data, sizeof(data), 0);
    }

    DWORD WINAPI Threading(LPVOID lpParam)
    {
        SOCKET *my_socket = (SOCKET*)lpParam;
        SocketAccept(my_socket);
    }

public:
    Net(void)
    {
        Header *obj_h = new Header();

        WSAInit(&obj_h->wsa_data, &obj_h->wsa_version);

        SocketInit(&obj_h->sock);
        SocketBind(&obj_h->sock, &obj_h->service);

        HANDLE thrd = CreateThread(NULL, 0, &Net::Threading, &obj_h->sock, 0, NULL);

        delete &obj_h;
    }
} Net;

int main(void)
{
    Net *obj_net = new Net();

    delete &obj_net;

    return 0;
}
4

2 回答 2

4

您不能使用 C++ 非静态成员函数。

使用静态的

于 2012-04-29T11:50:20.347 回答
1

Nestal 的回答是正确的—— CreateThread 需要一个函数,而不是一个方法。也就是说,这个样本还有很多其他问题,我不知道把它留在那里是否是负责任的事情。

首先,编码风格很奇怪:示例名义上是用 C++ 编写的,但实际上看起来像一个 C 程序。如果您打算从 C 切换到 C++,那么请注意,像这样使用“朋友”是您“做错了”的强烈暗示。

直接传递对朋友类属性的引用的奇怪风格隐藏了实际的代码问题:即使构建它也会失败很多,因为有许多竞争条件:套接字,作为引用传递给线程:&obj_h->sock将是Threading仍在运行时删除。即使它没有被删除,它(以及从多个线程引用的任何变量)也应该被限定,volatile以确保编译器不会优化将变量实际持久化到内存中。

即使您已将线程 proc 设置为“静态”、安全地传递参数、整理出竞争条件并正确 volatile 限定了任何共享变量,您仍需要添加线程同步以保护对共享变量的访问。同样 - 直接传递对值的引用的代码风格使得很难知道何时可以从不同的线程读取和写入变量 - 使得同步策略难以一致地实现。

祝你好运。

于 2012-04-30T09:16:10.803 回答