在c中通过套接字发送大文件

时间:2017-11-02 02:18:01

标签: c linux

因此,此代码适用于高达20KB的小文件,但是当我尝试发送或接收较大的文件时,它会在某些时候停止读取。客户端和服务器的两个功能,用于发送和接收文件。我知道它可能有一些泄漏和东西但我稍后会解决。起初我希望它能够正常工作。 BUF_SIZE = 512

// SENDING BYTES
void send_bytes(int connfd, int client_number, char **command_parts)
{
    FILE *fp;
    fp = fopen(command_parts[1], "r");
    int i = 0;
    // FINDING BYTE SIZE OF THE FILE
    fseek(fp, 0, SEEK_END); /* PUTTING FILE POINTER TO THE END OF THE FILE */
    int num_of_bytes = ftell(fp);
    fseek(fp, 0, SEEK_SET); /* RESETTING FILE POINTER TO THE BEGINNING OF THE FILE */
    char *sendbuff = malloc(num_of_bytes * sizeof(char));
    memset(sendbuff, '\0', num_of_bytes);
    // SENDING TOTAL BYTES TO SEND
    while (write(connfd, itoa(num_of_bytes), 10) < 0)
    {
    }
    printf("\nClient #%d --> Size of file sent: %d\n", client_number, num_of_bytes);

    // IF BYTES MORE THAN 512 SENDING IT IN PARTS
    if(num_of_bytes > BUF_SIZE)
    {
        int bytes_left_to_send = num_of_bytes;
        char *tempbuff = calloc(BUF_SIZE, sizeof(char));
        while(bytes_left_to_send > 0)
        {
            if(bytes_left_to_send >= BUF_SIZE)
            {
                // READING 512 BYTES AND PASSING IT TO TEMPBUFF
                for (i = 0; i < BUF_SIZE; i++)
                {
                    fread(&tempbuff[i], 1, 1, fp);
                }
                // SENDING BYTES
                while (write(connfd, tempbuff, BUF_SIZE) < 0)
                {
                }
                bytes_left_to_send = bytes_left_to_send - BUF_SIZE;
                memset(tempbuff, '\0', BUF_SIZE);
            }
            else
            {
                // READING 512 BYTES AND PASSING IT TO TEMPBUFF
                for (i = 0; i < bytes_left_to_send; i++)
                {
                    fread(&tempbuff[i], 1, 1, fp);
                }
                // SENDING BYTES
                while (write(connfd, tempbuff, bytes_left_to_send) < 0)
                {
                }
                bytes_left_to_send = bytes_left_to_send - bytes_left_to_send;
                memset(tempbuff, '\0', BUF_SIZE);
            }
        }
    }
    else
    {
        // READING EACH BYTE AND PASSING IT TO SENDBUFF
        for (i = 0; i < num_of_bytes; i++)
        {
            fread(&sendbuff[i], 1, 1, fp);
        }
        // SENDING BYTES
        while (write(connfd, sendbuff, num_of_bytes) < 0)
        {
        }
    }

    // FREEING MEMORY
    fclose(fp);
    free(sendbuff);
    printf("\nClient #%d --> File sent\n", client_number);
}
// RECEIVING BYTES
void recv_bytes(int connfd, int client_number, char **command_parts)
{
    int bytes_read = 0, bytes_read_in_total = 0, i = 0;
    char *num_of_bytes = malloc(10 * sizeof(char));
    char *recvbuff = NULL;
    FILE *fp;
    fp = fopen(command_parts[2], "w");
    // RECEIVING BYTES TO RECEIVE
    while (read(connfd, num_of_bytes, 10) < 0)
    {
    }
    printf("\nClient #%d --> Size of file received: %d\n", client_number, atoi(num_of_bytes));
    recvbuff = malloc(atoi(num_of_bytes) * sizeof(char)); /* ALLOCATING recvbuff WITH RECEIVED SIZE */
    memset(recvbuff, '\0', atoi(num_of_bytes));

    // IF BYTES MORE THAN 512 RECEIVING IT IN PARTS
    if(atoi(num_of_bytes) > BUF_SIZE)
    {
        int bytes_left_to_read = atoi(num_of_bytes);
        char *tempbuff = calloc(BUF_SIZE, sizeof(char));
        while(bytes_left_to_read > 0)
        {
            if(bytes_left_to_read >= BUF_SIZE)
            {
                // READING BYTES
                while (bytes_read = read(connfd, tempbuff, BUF_SIZE) < 0)
                {
                }
                bytes_read = strlen(tempbuff);
                // WRITING BYTES READ SO FAR TO THE FILE
                for (i = 0; i < bytes_read; i++)
                {
                    fwrite(&tempbuff[i], 1, 1, fp);
                }
                bytes_left_to_read = bytes_left_to_read - bytes_read;
                memset(tempbuff, '\0', BUF_SIZE);
            }
            else
            {
                // READING BYTES
                while (bytes_read = read(connfd, tempbuff, bytes_left_to_read) < 0)
                {
                }
                bytes_read = strlen(tempbuff);
                // WRITING BYTES READ SO FAR TO THE FILE
                for (i = 0; i < bytes_read; i++)
                {
                    fwrite(&tempbuff[i], 1, 1, fp);
                }
                bytes_left_to_read = bytes_left_to_read - bytes_read;
                memset(tempbuff, '\0', BUF_SIZE);
            }
        }
    }
    else
    {
        // RECEIVING BYTES
        while (bytes_read_in_total < atoi(num_of_bytes))
        {
            while (bytes_read = read(connfd, recvbuff, atoi(num_of_bytes)) < 0)
            {
            }
            bytes_read = strlen(recvbuff);
            bytes_read_in_total = bytes_read_in_total + bytes_read;

            // WRITING BYTES READ SO FAR TO THE FILE
            for (i = 0; i < bytes_read; i++)
            {
                fwrite(&recvbuff[i], 1, 1, fp);
            }
            memset(recvbuff, '\0', atoi(num_of_bytes));
        }
    }

    free(recvbuff);
    fclose(fp);
    printf("\nClient #%d --> File received\n", client_number);
}

1 个答案:

答案 0 :(得分:-1)

我以前做过这件事,我需要很长时间才能给你答案。 首先,您必须知道在调用send()时Linux内核不会发送整个缓冲区。其次,知道文件大小后需要的部分是以块的形式发送给接收端。我做了512个字节,你可以把它增加到你喜欢的任何地方。接收端也应该以块的形式接收,直到收到所有字节为止。

int sendall(int s, void *buf, int *len)
 {
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while (total < *len) {
    n = send(s, buf+total, bytesleft, 0);
    if (n == -1) {
        break;
    }
    total += n;
    bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}

使用此来接收整个缓冲区

int recvall(int s, void * buf,int *len)
{
// the workbuffer for storing currently received buffer
char workbuffer[*len];
// Holds the number of received bytes */
int total = 0;
// Holds the number of sent bytes
int n;
//holds the number of bytes left to received
int bytesleft = *len;
while (total < *len)
{
    // recv and append to workbuffer
    n = recv(s,workbuffer+total,bytesleft,0);
    if (n== -1 || n == 0) {
        break;
    }

    // increment total by the number of received bytes
    total += n;
    bytesleft -= n;
}
// Copy workbuffer to to buf
memcpy(buf,workbuffer,sizeof(workbuffer));
switch(n)
{
  case -1:
return -1;
  break;
  case 0:
return 0;
  break;
  default:
return total;
}

你可以下载我写的小程序quad(Qucik上传和下载)。基本上它应该演示如何传输大文件。这是https://www.dropbox.com/s/xpqhflgx6ps89vq/quad.zip?dl=0

wget https://www.dropbox.com/s/xpqhflgx6ps89vq/quad.zip?dl=0 -O quad.zip
unzip quad.zip
cd quad/src
make clean
sudo apt-get install libncurses-dev
make
#uploading: ./quad -v -u -i /home/me/myfile.txt -a 0.0.0.0 -p 4444
#downloading:  ./quad -v -d -l 4444 -o /home/me/Downloads