简体   繁体   中英

Read the whole file and send it via sockets

I made a server and client that should transfer files. I tried to make it read the whole file and send it. But now as I see it, I am having a problem. Server should automatically send the file when the client is connected. But the file is empty, and I don't know where the problem is You can see that I'm trying to send .txt file. But I would like in the future send a big file, but not bigger than 1MB.)

Edit:

Picture here: http://img819.imageshack.us/img819/8259/aadi.jpg

  • Left side: The file that I tried to send.
  • Right side: The file I received

在此处输入图片说明

The Problem: The file that I received has been damaged, and I can't use it.

Server:

#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;
}

Client:

#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;
}

The send API may not send all the data you requested to send. So, you have to pay attention to the return value, and retry the send from where the last send ended. As an example:

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

While you are doing something similar for your file transfer, you do not make sure this is the case for your file size.

When you send the file size, you only need to send the string that represents the size, not the entire MAX_PATH . The receiver then needs to parse the first string to determine the size, but any data read in after the end of the first string needs to be considered part of the file. However, since you are trying the send MAX_PATH , the receiver should receive the same amount. Your client code receives 1024 bytes, but there is no indication this is the same size as MAX_PATH .

The recv API may also return fewer bytes than requested. You use a loop to handle reading the file, but you may need a loop to read the entire message that contains the file size.

In your client receive loop, you are incrementing the data pointer. This makes it unusable to write out the file later. You already have Buffer though, so use that to write out your file.

fwrite(Buffer, 1, len, File);

If you encounter an error doing socket I/O, you can retrieve the error with WSAGetLastError() , or you can issue getsockopt() on the socket with the SO_ERROR option. These may return different values, but the error reason should be correlated.

Myself faced the same problem and after googling found that send() api can send a maximum data based on low level TCP buffers which are os dependent.So inorder to send a huge file we need to perform file chunking , ie send the file in the form of chunks.

`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;`

At the receiving end we need to have a recv() api called till the whole file content is read.

credits to:shacktar cplusplus.com

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM