2

C で記述されたクライアントで 4 つの send() を実行すると、サーバーは read() を 4 回実行する必要があるのでしょうか、それとも最初の読み取りで 4 つの send() がすべて一緒に読み取られるのでしょうか?

4

3 に答える 3

4

あなたを少し助けるために、あなたは基本的にあなた自身の質問にすでに答えています。

いわば「段階的に」行う必要があります。

クライアント:

int len = strlen(Filename) + 1; //Mind the terminating 0.
send(sock, (const char *)&len, sizeof(int), 0);
send(sock, Filename, len, 0);  //Sending the filename
send(sock, &FileSize, sizeof(int), 0);
send(sock, FileBuf, FileSize, 0);

このコードは途中でデータ全体を送信します (ファイル全体が「FileBuf」変数にあると仮定します)。

サーバ:

int len;
char *FileBuf, FileName[20];
recv(sock, &len, sizeof(int), 0);  //Receives the filename length. (4 Bytes)
recv(sock, FileName, len, 0);      //Receives the filename (x bytes)
recv(sock, &len, sizeof(int), 0);  //Receives the file length (again, 4 bytes)
FileBuf = new char[len];           //Creates sufficient space in memory.
recv(sock, FileBuf, len, 0);       //Receives the file into the appropriate variable.

これは絶対的な最低限のバリアントであり、あまり堅実ではありませんが、アイデアを得る必要があります。

より堅牢なアプローチでは、recv() と send() の戻り値を確認する必要があります。どちらも、この呼び出しで処理されたバイト数を返します。この値が「0」の場合、接続が相手側によって閉じられたことを意味します。(主にrecv())。-1 の場合は、何か問題が発生したことを意味し、errno変数を確認する必要があります。

すべてがうまくいけば、送信した/受信しようとしたバイトの正確な量に等しくなります。

ただし、「len」(または 0 または -1) でない場合は、このような小さなラッパーを書くことができます。

unsigned char Recv(int sock, void *target, int Len) {
    unsigned char *ptr = (unsigned char *)target, Ret = 0;
    int RecvBytes = 1;
    while(Len && !Ret) {
        RecvBytes = recv(sock, ptr, Len, 0);
        if(!RecvBytes) Ret = 1;
        else if(RecvBytes == -1) Ret = errno;
        else {
            Len -= RecvBytes;
            ptr += RecvBytes;
        }
    }
    return Ret;
}

このコードの動作: 期待していたすべてのデータ (Lenパラメーター) を受信するか、エラーが発生するまで、受信を続けます。すべてがうまくいくと、「0」が返されます。これは で確認できますif(!Recv())

別の便利なラッパー関数 (いわばショートカット) は次のとおりです。

uint32_t RecvInt(int sock) {
    uint32_t Ret;
    Recv(sock, &Ret, sizeof(Ret));
    return ntohl(Ret);
}

この関数は、符号なし int を 1 つだけ受け取り、エンディアンをネットワーク バイト オーダーからホスト バイト オーダーに修正します。(ネットワーク バイト オーダーは常にビッグ エンディアンです。ホスト バイト オーダーは多くの場合、リトル エンディアンです)

これらのラッパー関数を使用すると、コードは次のように変更できます。

uint32_t len;
char *FileBuf, FileName[20];
len = RecvInt(sock);               //Receives the filename length. (4 Bytes)
Recv(sock, FileName, len);         //Receives the filename (x bytes)
len = RecvInt(sock);               //Receives the file length (again, 4 bytes)
FileBuf = new char[len];           //Creates sufficient space in memory.
Recv(sock, FileBuf, len);          //Receives the file into the appropriate variable.
于 2013-02-27T15:49:24.027 に答える
1

ストリーム ソケット (TCP など)の場合:送信側で行われた呼び出しのsend()数に違いはありません。write()データは、1 チャンクから 1 バイトの n チャンク (n は送信されたバイト数)、またはその間のチャンクで返される可能性があります。

データグラム ソケット (UDP など) の場合:recv()またはの各recvmsg()呼び出しは、相手側から送信された 1 つの完全なデータグラムを返します。recv()またはの呼び出しの数recvmsg()は、送信されたデータグラムの数と同じである必要があります。recv()データグラムソケットから読み取る場合は推奨されread()ますが、同じように動作するはずです。

于 2013-02-27T15:44:42.393 に答える
0

との数は同じwrite()read()ある必要はありません。write()はすべてのデータを 1 つの部分に書き込みますが、他のコンピュータread()ではそれをいくつかのチャンクでしか受信できない可能性があり、その逆も同様です。そのため、これらの関数の戻り値を常に確認し、部分的なデータ転送のみが発生した場合は、残りの送受信を続行する必要があります。

于 2013-02-27T15:42:00.007 に答える