0

こんにちは、通常はファイル名であるクライアントからの名前を受け入れるサーバーアプリケーションを作成しました。ファイルを開き、内容をバッファーに読み取り、使用してイーサネット経由でバッファーを送信します。send()しかし、クライアント側で問題が発生しますここで、すべてのバイトが正常に受信されません。送信したものの一部しか受信しません。

参考までに、サーバー側のコード スニペットを次に示します。

サーバー:

fp = fopen(filename,"r+");  
        strcpy(str,"");
        fseek(fp, 0L, SEEK_END);
        size = ftell(fp);
        fseek(fp, 0L, SEEK_SET);
        fread(str, size, 1,fp);
        fclose(fp); 
        printf("Size of the file is : %d\n",size);
        sprintf(filename, "%d", size);
        n = send(nsd, filename, strlen(filename), 0);

while(size > 0){
            n = send(nsd, str, strlen(str), 0);
            printf("%d bytes sent successfully\n",n);           
            if(n == 0) break;
            sentbytes = sentbytes + n;
            size = size - sentbytes;
        }

クライアント アプリの作成を手伝ってください。現在、どのように作成すればよいか混乱しています。すべてのバイトが正常に受信されるまでクライアントが実行し続けるように、このrecv()部分をループに配置しますか?while(1)

4

4 に答える 4

3

編集済みまず、両方を同時にチャンクに
することができます。 TCP 経由でデータを転送しているため、データはメッセージではなくストリームとして確実に転送されることに注意してください。したがって、順序を除いて、データがどのように受信されるかについて仮定しないでください。read from the filewrite to the socket

書き方は次のとおりです。

open socket
open file
size_of_file = read_file_size(file);
send(socket, &size_of_file, sizeof(int), ...)
while (all is written)
    read fixed chunk from file
    write as much was read to the socket
cleanup // close file, socket

そのrecv部分については、ファイルサイズを整数として送信し、サーバーから送信しているバイトと同じ数のバイトを受信するまでwhileループで読み取り続けるのが最善だと思います。

こんな感じです:

recv(socket, &size_of_msg, sizeof(int), ...)
while(all is read)
    read fixed chunk from the socket
cleanup
于 2012-05-20T12:42:17.180 に答える
3

ソケットを介してメッセージを送信する方法に少なくともいくつかの問題があります。

最初に fread の man ページから:

  The  function  fread()  reads  nmemb  elements of data, each size bytes
   long, from the stream pointed to by stream, storing them at  the  loca-
   tion given by ptr.

あなたがしようとしているのはこれです:

fread(str, size, 1,fp);

私はあなたが何を意味したと思います

 fread(str, 1,size,fp);

問題が発生することはありませんが。

しかし、問題はここにあります:

    n = send(nsd, str, strlen(str), 0);
        printf("%d bytes sent successfully\n",n);           
        if(n == 0) break;
        sentbytes = sentbytes + n;
        size = size - sentbytes;

正常に送信されたバイト数を減らすことで「サイズ」を減らしていますが、データが送信される新しいバッファーの場所を指すように str をどこに拡張していますか?これは、バッファーの最初のバイトのみを繰り返し再送信します。

        str += n; //Assuming str is char*

あなたの問題を解決します。

于 2012-05-20T13:07:15.713 に答える
2

「recv() 部分を while(1) ループに配置して、すべてのバイトが正常に受信されるまでクライアントが実行し続けるようにしますか?」

そんな感じ。呼び出しが送信されたすべてのものを受け取ったと思い込まないでくださいrecv()-- tcp/ip はメッセージをより低いレベルでパケットに分割し、任意の時点で実際に受信されたデータの量を読み取った後に recv() が戻ります。受信者がどれだけ読むべきかを知るためにメッセージの長さを示すためにある種のプロトコルを使用する必要がある場合を除いて、それについて直接心配する必要はありません。

char buffer[4096];
int msgsz = 600, // see below
    sofar = 0,
    cur;

while (sofar < msgsz) {
    cur = recv (
        socket_fd,
        &buffer[sofar],
        msgsz - sofar,
        0
    );
    if (cur == -1) {
        // error
        break;
    } else if (cur == 0) {
        // disconnected
        break;
    }
    sofar += cur;
} 

WRT msgsz、最初に読み取られる固定長ヘッダーのどこかにこれを含めます。uint32_tその単純なバージョンは、 、つまり長さの int を含むわずか 4 バイトである可能性があります。数値を含むヌル終了文字列を使用することもできますが、それ'\0'は、見つかるまで読み取ることを意味します。

于 2012-05-20T12:41:43.153 に答える
2

使用strlenは適切ではないようです。あなたはファイルを読み、その長さを知っていstrlenます。同じ結果が得られる (冗長なので) か、別の結果が得られる (バグです) かのどちらかです。

于 2012-05-20T12:44:24.807 に答える