0

TCP レベルでネットと連携するツールの開発を開始しましたが、次の問題が発生しました。

  • Winsock のaccept()関数のスレッドを作成する

私はググって参考文献を探し、新しいスレッドの作成に関する情報があるところならどこでも探しました:

  • プレフィックスに DWORD WINAPI (unsigned long __stdcall) が必要です
  • LPVOID 引数を受け入れる必要があります

そのような関数は、LPTHREAD_START_ROUTINE 構造体として CreateThread() 関数の第 3 引数として使用されます。

しかし、コンパイル後に次のエラーが発生しました。

(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、コンパイラが変数を実際にメモリに永続化して最適化しないように修飾する必要があります。

スレッド プロシージャを「静的」にし、パラメータを安全に渡し、競合状態を整理し、共有変数を正しく volatile 修飾した後でも、共有変数へのアクセスを保護するためにスレッド同期を追加する必要があります。繰り返しになりますが、値への参照を直接渡すコード スタイルでは、変数がいつ異なるスレッドから読み書きされるかを知ることが難しくなり、同期戦略を一貫して実装することが難しくなります。

幸運を。

于 2012-04-30T09:16:10.803 に答える