1

TCP/IP ネットワーク クライアント通信用のクラスを作成しています。クラス ヘッダーで、SOCKET メンバーを作成します。このクラスには、WSAStartup を呼び出してバージョンを確認するためのメソッドも含まれています。接続を確立するメソッドは、まず WSAStartup を呼び出し、次に socket() 関数を呼び出して SOCKET メンバーを初期化します。以下のコードを参照してください。これが「正しい」のか、それとももっと良い方法があるのか​​ 疑問に思っています。

ヘッダー ファイル:

/*network.h*/
public class IPnetwork
{
private:
    WSADATA wsaData ;
    SOCKET hSocket ;
    sockaddr_in socketAddress ;
    static const int SERVER_PORT = 502 ;
    unsigned long int = serverIP ;

public:
    IPnetwork(char* serverIPaddress) ;
    bool Connect() ;
    bool Disconnect() ;
    ~IPnetwork() ;

private:
    bool startWinSock() ;
} ;

ソースコード:

/*network.cpp*/
IPnetwork::IPnetwork(char* serverIPaddress)
{
    serverIP = inet_addr(serverIPaddress) ;
}

bool IPnetwork::Connect()
{
     /* start winsock */
    if(!startWinSock())
    {
        return false ; /* winsock problem */
    }

    /* Create socket */
    if ((hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        return false ; /* could not create socket */
    }

    /* fill socket address structure */
    socketAddress.sin_family = AFINET ;
    socketAddress.sin_port = htons(SERVER_PORT) ;
    socketAddress.sin_addr.S_un.S_addr = serverIP ;

    /* connect */
    if(connect(hSocket,reinterpret_cast<sockaddr*>(&socketAddress), sizeof(sockAddr))!=0)
    {
        return false ; /* could not connect*/
    }

    return true ;

}

bool IPnetwork::startWinSock()
{
    if(WSAStartup(MAKEWORD(REQ_WINSOCK_VER,0),&wsaData)==0)
    {
        /* Check if major version is at least REQ_WINSOCK_VER */
        if (LOBYTE(wsaData.wVersion) < REQ_WINSOCK_VER)
        {
            return false ; /* winsock started but version is too low */
        }
        else
        {
            return true ; /* winsock started with right version*/
        }
    }
    else
    {
        return false ; /* winsock not started */
    }

}
4

3 に答える 3

4

SOCKETtype の変数を定義することと、そのコンストラクターがいつ実行されるかが心配ですか?

SOCKETはソケット識別子を保持する C 互換のプレーン オールド データの整数型であるため、これは問題ではありません。それはオブジェクトではありません。変数自体に関連する重要な構築や破棄はありません。

于 2013-03-11T16:33:58.713 に答える
2

WSAStartup()を呼び出す前に呼び出す必要があります。socket()そうしないと、WSANOTINITIALISEDエラーが返されます。

WSAStartup()何度でも呼び出せます。WSAStartup()1 回だけ呼び出すことをお勧めしますが、WinSock は参照カウントされるため、必要に応じて複数回呼び出すことができます。WSACleanup()成功するたびに 1 回呼び出すようにする必要がありますWSAStartup()。そうしないと、参照カウントが不均衡になります。たとえばWSAStartup()、コンストラクタを呼び出しWSACleanup()て、デストラクタを呼び出すことができます。

public class IPnetwork
{
private:
    WSADATA wsaData ;
    bool wsaInit;
    ...

public:
    IPnetwork(char* serverIPaddress) ;
    ~IPnetwork() ;
} ;

.

IPnetwork::IPnetwork(char* serverIPaddress)
{
    wsaInit = (WSAStartup(MAKEWORD(REQ_WINSOCK_VER,0), &wsaData) == 0);
    ...
}

IPnetwork::~IPnetwork()
{
    if (wsaInit) WSACleanup();
}

bool IPnetwork::Connect()
{
    if (!wsaInit)
        return false ; /* winsock problem */
    ...
}

私は通常、代わりに別のシングルトン クラス内でそれらを呼び出しますが。

于 2013-03-11T18:40:58.693 に答える
1

あなたがやっていることは問題ないという@Benに同意しますが、私は個人的にあなたのコードのメインラインからこの醜さを取り除こうとします。IMO、これは、次のようなヘッダーでグローバル変数を作成することが合理的なまれなケースの 1 つです。

#ifndef WS_INITIATOR_INC_
#define WS_INITIATOR_INC_

#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

#include <stdexcept>

struct bad_version : public std::logic_error {
    bad_version(std::string const &s) : logic_error(s) {}
};

struct winsock { 
    static const int version = 2;
    WSADATA wsaData;

    winsock() { 
        WSAStartup(MAKEWORD(2, 2),&wsaData);
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
            throw bad_version("Could not initialize WinSock 2.2");
    }
    ~winsock() { 
        WSACleanup();
    }
} ws_initiator;

#endif

main.cppこれを(または を含むファイルに付けた任意の名前)に含めるmainと、ソケットの初期化/クリーンアップ (および適切なライブラリとのリンク) が自動化されます。

于 2013-03-11T16:56:56.310 に答える