0

Winsock2 を使用して Windows Socket 経由で整数を送信する方法を探していました。私は、すべてではないにしても、スタックオーバーフローで人々が尋ねた質問のほとんどを見てきました。

これは、整数を送信するクライアント用に私が持っているものです:

struct struct_var
{
    int Packet;
    int Number;
};

struct_var *arraystruct;

arraystruct = (struct_var *) malloc(sizeof(struct_var));
(*arraystruct).Packet = 100;
(*arraystruct).Number = 150;
int bytes = send(client,(char*)arraystruct,sizeof(*arraystruct),0);`

私も次を使用して送信しようとしました:

int int_data = 4;
int bytes = send(server, (char*) &int_data, sizeof(int), 0);`

これは別のstackoverflowの質問で推奨されました これは受信側であり、これも推奨されました:

int int_data;
int bytes = recv(server, (char*) &int_data, sizeof(int), 0);
cout << int_data;`

これらを実行すると、コマンドラインから得られる出力は次のとおりです。-858993460

なぜこれが起こっているのか誰にも分かりますか?

また、これは複数の種類のコンピューターに送信されるため、正しいバイト順序が必要です。私を助けてくれる人に前もって感謝します

完全なサーバー コード:

int main() {
WSADATA wsaData;
WORD version;
int error;

version = MAKEWORD(2, 0);

error = WSAStartup(version, &wsaData);

if ( error != 0 )
{
    return FALSE;
}

if ( LOBYTE( wsaData.wVersion ) != 2 ||
     HIBYTE( wsaData.wVersion ) != 0 )
{
    WSACleanup();
    return FALSE;
}


SOCKET server;

server = socket(AF_INET, SOCK_STREAM, 0);

sockaddr_in sin;

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(5555);

if (bind( server, (SOCKADDR*)&sin, sizeof(sin) ) == SOCKET_ERROR ){
    DWORD ec=WSAGetLastError();
    cerr << hex << "bind ERROR" << ec << endl;
    return FALSE;
}

if ( listen( server, SOMAXCONN ) == SOCKET_ERROR ) {
    DWORD ec=WSAGetLastError();
    cerr << hex << "listen ERROR" << ec << endl;
    return FALSE;
}

SOCKET client;
int length;

    while(1) {

    if ( listen( server, SOMAXCONN ) == SOCKET_ERROR ) {
    DWORD ec=WSAGetLastError();
    cerr << hex << "listen ERROR" << ec << endl;
    return FALSE;
    }

    length = sizeof sin;
    client = accept( server, (SOCKADDR*)&sin, &length );
    cout << "Client connected" << endl;
    cout << "Sending Instructions..." << endl;

    int int_data;
    int bytes;

    bytes = recv(client, (char*) &int_data, sizeof(int), 0);

    cout << int_data << endl;
}

}

}

完全なクライアント コード:

int main() {

WSADATA wsaData;
WORD version;
int error;

version = MAKEWORD(2, 0);

error = WSAStartup(version, &wsaData);

if ( error != 0 )
{
    return FALSE;
}

if ( LOBYTE( wsaData.wVersion ) != 2 ||
     HIBYTE( wsaData.wVersion ) != 0 )
{
    WSACleanup();
    return FALSE;
}

SOCKET client;

client = socket( AF_INET, SOCK_STREAM, 0 );

sockaddr_in sin;

memset( &sin, 0, sizeof sin );

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_port = htons(5555);

if ( connect(client, (SOCKADDR*)(&sin), sizeof sin ) == SOCKET_ERROR ){
    return FALSE;
}

int int_data = 4;
    int bytes = send(client, (char*) &int_data, sizeof(int), 0);

}

4

3 に答える 3

3

問題は次のとおりです。

int bytes = recv(server, (char*) &int_data, sizeof(int), 0);

次のようにする必要があります。

int bytes = recv(client, (char*) &int_data, sizeof(int), MSG_WAITALL);

問題の原因ではない他のいくつかの気の利いたことですが、知っておく必要があります。

  1. サーバー ソケットを 10.0.0.5 にバインドしないでください。0 (INADDR_ANY) にバインドします。そうすれば、IP アドレスが 10.0.0.6 のマシンでコードを実行しても、コードは機能します。

  2. ビッグエンディアン ボックスとの相互運用には、htonl()、htons()、ntohs()、および ntohl() を使用します。

  3. ソケット呼び出しからの戻り値を常に確認してください。recv が 0 または -1 を返す場合、リモート側が切断されたことを意味します。(技術的には、0 はクライアントが送信を停止したことを意味しますが、シャットダウンのハーフクローズ処理を行っていない限り、クライアントが切断されたことを意味します)。

  4. TCP ソケットはメッセージ指向ではなく、ストリーム指向です。つまり、recv() に N バイトを取得するように指示したからといって、N バイトが返されるわけではありません。IP フラグメンテーション、TCP セグメンテーション、およびその他の要因により、recv() が部分的なデータを返す可能性があります。必要に応じて MSG_WAITALL フラグを使用します。

于 2012-06-02T20:47:11.377 に答える
1

あなたはこれを自分でほとんど不可能にしています。コードから始めるのではなく、プロトコル仕様から始めます。HTTP、IMAP など、TCP を使用する既存のプロトコルの仕様を調べて、プロトコルの仕様に何を含める必要があるかを確認できます。

プロトコル仕様では、送受信されるすべてのことをバイトレベルで説明する必要があります。接続がどのように確立され、切断されるかを説明する必要があります。いずれかの端から切断された接続がどのように検出されるかを説明する必要があります。プロトコルにアプリケーション層メッセージがある場合は、それらがどのように区切られているか、および受信者がメッセージの終わりを見つける方法を説明する必要があります。誰がいつ送信するかを指定する必要があります。

その後、デバッグは簡単です。次のフローチャートに従います。

1) サーバーは仕様に従っているか? そうでない場合は、サーバーが壊れています。

2) クライアントは仕様に従っているか? そうでない場合、クライアントは壊れています。

3) それでも動かない場合は、仕様が壊れています。

これにより、サーバーとクライアントが確実に連携することが可能になります。そうでない場合は、どちら側を修正する必要があるかを知ることができます。

プロトコル仕様のスケッチには 1 ~ 2 時間しかかかりません。節約された時間はそれだけの価値があることを約束します。必要なのは、何かがうまくいかないときに間違った端を1回変更するだけです(そして、正しい場所の1つを修正したために、多くのものが新しく壊れていることがわかります)。さらに、おまけとして、他の実装を作成することも可能です。

于 2012-06-02T22:52:38.093 に答える