2

ファイルを転送するサーバーとクライアントを作成しました。ファイル全体を読み取って送信するようにしました。しかし、今見ると、私は問題を抱えています。クライアントが接続されると、サーバーは自動的にファイルを送信する必要があります。しかし、ファイルは空で、どこに問題があるのか​​わかりません.txt ファイルを送信しようとしていることがわかります。しかし、将来的には大きなファイルを送信したいと思いますが、1MB を超えないようにしてください。)

編集:

写真はこちら: http://img819.imageshack.us/img819/8259/aadi.jpg

  • 左:送信しようとしたファイル。
  • 右側:受け取ったファイル

ここに画像の説明を入力

問題: 受け取ったファイルが破損していて、使用できません。

サーバ:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;

#pragma comment(lib, "Ws2_32.lib")
#define Port 6000

SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);

int main()
{
    WSAStartup(MAKEWORD(2, 2), &Winsock);    // Start Winsock

    if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2)    // Check version
    {
        WSACleanup();
        return 0;
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    ZeroMemory(&Addr, sizeof(Addr));
    Addr.sin_family = AF_INET;
    Addr.sin_port = htons(Port);  
    bind(Socket, (sockaddr*)&Addr, sizeof(Addr));

    if(listen(Socket, 1) == SOCKET_ERROR)
    {
        printf("listening error\n");
    }
    else
    {
        printf("listening ok\n");
    }

    if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
    {
        char *ClientIP = inet_ntoa(IncomingAddress.sin_addr);
        int ClientPort = ntohs(IncomingAddress.sin_port);
        printf("Client conncted!\n");
        printf("IP: %s:%d\n", ClientIP, ClientPort);

        printf("Sending file .. \n");

        FILE *File;
        char *Buffer;
        unsigned long Size;

        File = fopen("C:\\Prog.rar", "rb");
        if(!File)
        {
            printf("Error while readaing the file\n");
            getchar();
            return 0;
        }

        fseek(File, 0, SEEK_END);
        Size = ftell(File);
        fseek(File, 0, SEEK_SET);

        Buffer = new char[Size];

        fread(Buffer, Size, 1, File);
        char cSize[MAX_PATH];
        sprintf(cSize, "%i", Size);

        fclose(File);
        send(Sub, cSize, MAX_PATH, 0); // File size

        //int len = Size;
        //char *data = Buffer;

        int Offset = 0;
        while(Size > Offset)
        {
            int Amount = send(Sub, Buffer + Offset, Size - Offset, 0);

            if(Amount <= 0)
            {
                cout << "Error: " << WSAGetLastError() << endl;
                break;
            }
            else
            {
                Offset += Amount;
                printf("2\n");
            }
        }


        free(Buffer);
        closesocket(Sub);
        closesocket(Socket);
        WSACleanup();
    }

    getchar();
    return 0;
}

クライアント:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;

#pragma comment(lib, "Ws2_32.lib")

SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);

int main()
{
    WSAStartup(MAKEWORD(2, 2), &Winsock);    // Start Winsock

    if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2)    // Check version
    {
        WSACleanup();
        return 0;
    }

     Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    ZeroMemory(&Addr, sizeof(Addr));    // clear the struct
    Addr.sin_family = AF_INET;    // set the address family
    Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    Addr.sin_port = htons(6000);    // set the port

    if(connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
    {
        printf("Connection failed !\n");
        getchar();
        return 0;
    }

    printf("Connection successful !\n");

    printf("Receiving file .. \n");



    int Size;
    char *Filesize = new char[1024];

    if(recv(Socket, Filesize, 1024, 0)) // File size
    {
        Size = atoi((const char*)Filesize);
        printf("File size: %d\n", Size);
    }

    char *Buffer = new char[Size];

    //int len = Size;
    //char *data = Buffer;

    int Offset = 0;
    while(Size > Offset)
    {
        int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);

        if(Amount <= 0)
        {
            cout << "Error: " << WSAGetLastError() << endl;
            break;
        }
        else
        {
            Offset += Amount;
            printf("2\n");
        }
    }

    FILE *File;
    File = fopen("Prog.rar", "wb");
    fwrite(Buffer, 1, Size, File);
    fclose(File);

    getchar();
    closesocket(Socket);
    WSACleanup();
    return 0;
}
4

2 に答える 2

4

API は、send送信を要求したすべてのデータを送信しない場合があります。そのため、戻り値に注意して、最後に送信が終了したところから再送信する必要があります。例として:

offset = 0;
while (offset < bufsize) {
    r = send(socket, buf+offset, bufsize-offset);
    if (r <= 0) break;
    offset += r;
}

ファイル転送に同様のことを行っている間、これがファイルサイズに当てはまるかどうかを確認しません。

ファイル サイズを送信する場合は、ファイル全体ではなく、サイズを表す文字列のみを送信する必要がありますMAX_PATH。次に、受信者は最初の文字列を解析してサイズを決定する必要がありますが、最初の文字列の末尾の後に読み込まれたデータはファイルの一部と見なす必要があります。ただし、送信を試みているためMAX_PATH、受信者は同じ金額を受け取る必要があります。クライアント コードは 1024 バイトを受け取りますが、これが と同じサイズであることを示すものはありませんMAX_PATH

API は、recv要求されたよりも少ないバイト数を返す場合もあります。ファイルの読み取りを処理するためにループを使用しますが、ファイル サイズを含むメッセージ全体を読み取るためにループが必要になる場合があります。

クライアント受信ループでは、dataポインターをインクリメントしています。これにより、後でファイルを書き出すことができなくなります。ただし、既に持ってBufferいるので、それを使用してファイルを書き出します。

fwrite(Buffer, 1, len, File);

ソケット I/O でエラーが発生した場合は、 を使用してエラーを取得するか、オプションを使用してソケットで をWSAGetLastError()発行できます。これらは異なる値を返す場合がありますが、エラーの理由は相関している必要があります。getsockopt()SO_ERROR

于 2013-03-02T16:09:20.300 に答える
0

私自身も同じ問題に直面し、Google で調べたところ、send() API は OS に依存する低レベルの TCP バッファに基づいて最大のデータを送信できることがわかりました。そのため、巨大なファイルを送信するには、ファイルのチャンクを実行する必要があります。つまり、塊の形。

`const int FILE_CHUNK_SIZE = 2000; 

 //get file size
 ifstream file("myFile.file", ios::binary);
 file.seekg(0, ios::end);
 unsigned int fileSize = file.tellg();
 file.close();

 //get the file
 char* fileBuffer = new char[fileSize];
 file.open("myFile.file", ios::binary);
 file.seekg (0, ios::beg);
 file.read (fileBuffer, fileSize);
 file.close();

 //send file in chunks
 unsigned int bytesSent = 0;
 int bytesToSend = 0;

 while(bytesSent < fileSize)
 {
     if(fileSize - bytesSent >= FILE_CHUNK_SIZE)
        bytesToSend = FILE_CHUNK_SIZE;
    else
        bytesToSend = fileSize - bytesSent;
    send(ConnectSocket, fileBuffer + bytesSent, bytesToSend, 0 );
    bytesSent += bytesToSend;
}
delete [] fileBuffer;`

受信側では、ファイルの内容全体が読み取られるまで recv() API を呼び出す必要があります。

クレジット: shacktar cplusplus.com

于 2015-01-15T14:18:04.277 に答える