c - 通过C中的套接字发送大文件

标签 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);
}

最佳答案

我之前已经做过,给您答案将花费我很多时间。
首先,您必须知道,当调用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;
}


您可以下载我编写的四小程序(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

关于c - 通过C中的套接字发送大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47066539/

相关文章:

python - 如何保存运行 python 程序的状态以便稍后恢复?

java - 好的开源软件来分析

c - 与之前 fork 的子进程共享一个套接字

c++ - 地震 2 md2 文件格式(理论)

c++ - 如何使用原始套接字正确重现 TCP 协议(protocol) 3 次握手?

linux - xz压缩在centos上安装

c - C 二进制中的整数 : viewing it using readelf, objdump 或类似

Linux:如何将整个数据包发送到另一台主机上的特定端口?

c++ - 在编译时检测处理器是否有 RDTSCP

c - 函数指针查询