【问题标题】:Segmentation Fault in Client File Transfer客户端文件传输中的分段错误
【发布时间】:2021-07-02 19:03:00
【问题描述】:

我在运行这个文件传输程序时遇到了分段错误,经过数小时的查看似乎无法找到问题所在。我试图只包含所涉及的相关代码。程序将请求的文件分割成块(在本例中为 2),然后将这些单独的文件块发送给另一个客户端。我相信在代码的发送/接收文件部分发生分段错误:

while(((bytes_sent = sendfile(peer_socket_server, fd, &off, SIZE)) > 0) && (bytes_remaining > 0)){
    printf("bytes sent: %d\n", bytes_sent);
    bytes_remaining -= bytes_sent;
}

while(((bytes_received = recv(peer_socket_server, data, SIZE, 0)) > 0) && (bytes_remaining > 0)){
    printf("bytes recv: %d\n", bytes_received);
    fwrite(data, sizeof(char), bytes_received, fp);
    bytes_remaining -= bytes_received;

}

我输入了一些打印语句来检查我收到了什么:

    recv newfilename: file1_chunk0.txt
    recv newfilesize: 1024
    bytes recv: 512
    bytes recv: 512
    recv newfilename: 
    recv newfilesize: 1024
    Segmentation fault (core dumped)

我的第二个客户端正在成功下载第一个块,但第二个块文件应该是 file1_chunk1.txt,它没有被接收/下载。我正在从我编写的一个简单的文件传输程序中重用上面的文件传输代码,该程序有效,这就是为什么我很困惑为什么这不起作用。

代码:

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <netdb.h>
#include <sys/time.h>
#include <pthread.h>
#include "shared.h"
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>

#define SIZE 512
#define NUMPEERS 2
#define CHUNKSIZE 1024

void SendFileToPeer();
void* GetFileFromPeer(void* pstruct);

typedef struct thread_args{
    int peer_port_server;
    char *filename;
    int chunks;
    int offset;
    int filesize;
} astruct;


int peer_socket, peer_port;

int main(int argc, char **argv){
    int chunks;
    int filesize = 2048;
    int peercount = 1;
    int peers[1] = {8002};
    char filename[SIZE] = "file1.txt";

    chunks = filesize / CHUNKSIZE;
    chunks = chunks / peercount;

    pthread_t threads[NUMPEERS];
    astruct argstruct[NUMPEERS];
    for (int i = 0; i < NUMPEERS; i++){
        if(peers[i] != 0 ){
            argstruct[i].peer_port_server = peers[i];
            argstruct[i].filename = strdup(filename);
            argstruct[i].chunks = chunks;
            argstruct[i].offset = i;
            argstruct[i].filesize = filesize;
            pthread_create(&threads[i], NULL, GetFileFromPeer, &argstruct[i]);
        }
    }

    for(int i = 0; i < NUMPEERS; i++){
        pthread_join(threads[i], NULL);
    }
    return 0;
}


void* GetFileFromPeer(void* pstruct){
    int peer_port_server;
    char filename[SIZE];
    char newfilename[600];
    int chunks;
    int offset;
    int filesize;
    int newfilesize;
    astruct *argstruct = (astruct *)pstruct;

    peer_port_server = argstruct->peer_port_server;
    strcpy(filename, argstruct->filename);
    free(argstruct->filename);
    chunks = argstruct->chunks;
    offset = argstruct->offset;
    filesize = argstruct->filesize;

    //Connect to peer server to download file
    struct sockaddr_in peer_socket_server_addr;
    int peer_socket_server;
    int peer_port_t;

    peer_socket_server = socket(AF_INET, SOCK_STREAM, 0);
    if (peer_socket_server < 0) {
        printf("Error creating socket dest\n");
        exit(1);
    }

    peer_socket_server_addr.sin_family = AF_INET;
    peer_socket_server_addr.sin_port = htons(peer_port_server);
    peer_socket_server_addr.sin_addr.s_addr = INADDR_ANY;

    if (connect(peer_socket_server, (struct sockaddr *)&peer_socket_server_addr, sizeof(peer_socket_server_addr)) < 0) {
        printf("Error connecting to peer server\n");
        exit(1);
    }
    
    recv(peer_socket_server, &peer_port_t, sizeof(int), 0);
    printf("Connected to peer server on port %d\n", peer_port_t);

    FILE *fp;
    int bytes_remaining;
    int bytes_received;
    char data[SIZE];

    send(peer_socket_server, filename, SIZE, 0);
    send(peer_socket_server, &chunks, sizeof(int), 0);
    send(peer_socket_server, &offset, sizeof(int), 0);

    for (int i = 0; i < chunks; i++){
        recv(peer_socket_server, newfilename, 600, 0);
        printf("recv newfilename: %s\n", newfilename);
        fp = fopen(newfilename, "w");

        recv(peer_socket_server, &newfilesize, sizeof(int), 0);
        printf("recv newfilesize: %d\n", newfilesize);
        bytes_remaining = newfilesize;
        while(((bytes_received = recv(peer_socket_server, data, SIZE, 0)) > 0) && (bytes_remaining > 0)){
            printf("bytes recv: %d\n", bytes_received);
            fwrite(data, sizeof(char), bytes_received, fp);
            bytes_remaining -= bytes_received;
        }
        fclose(fp);
    }
    close(peer_socket_server);
}

void SendFileToPeer(){
    struct sockaddr_in peer_socket_server_addr;
    int peer_socket_server;
    socklen_t len = sizeof(peer_socket_server_addr);

    //Loop for multiple peers to connect
    while(1)
    {
        char filename[SIZE];
        int chunks;
        int offset;
        int byte_offset;
        int filesize;
        char newfilename[600];
        char tempfilename[SIZE];
        int bytes_sent = 0;
        off_t off = 0;
        int bytes_remaining;
        FILE *fp1, *fp2;
        char buf[SIZE];
        int remaining;
        int fd;
        struct stat filestat;

        peer_socket_server = accept(peer_socket, (struct sockaddr*)&peer_socket_server_addr, &len);

        send(peer_socket_server, &peer_port, sizeof(int), 0);
        printf("\nPeer %d has connected\n", peer_socket_server);

        recv(peer_socket_server, filename, SIZE, 0);
        recv(peer_socket_server, &chunks, sizeof(int), 0);
        recv(peer_socket_server, &offset, sizeof(int), 0);

        printf("Sending file %s to peer %d\n", filename, peer_socket_server);

        offset = offset * chunks;
        byte_offset = offset * CHUNKSIZE;
        strncpy(tempfilename, filename, SIZE);
        tempfilename[strlen(tempfilename)-4] = '\0';

        fp1 = fopen(filename, "r");
        for (int i = 0; i < chunks; i++){
            sprintf(newfilename, "%s_chunk%d.txt", tempfilename, i+offset);
            send(peer_socket_server, newfilename, 600, 0);
            printf("sent file: %s\n", newfilename);

            fp2 = fopen(newfilename, "w");
            remaining = CHUNKSIZE;
            fseek(fp1, byte_offset, SEEK_SET);
            while(fread(buf, SIZE, 1, fp1) != 0){
                if(remaining > 0){
                    fwrite(buf, SIZE, 1, fp2);
                    remaining -= SIZE;
                }
            }
            byte_offset += CHUNKSIZE;
            fclose(fp2);

            //Send file
            fd = open(newfilename, O_RDONLY); 
            fstat(fd, &filestat);
            filesize = filestat.st_size;
            bytes_remaining = filesize;

            send(peer_socket_server, &filesize, sizeof(int), 0);
            printf("sent size: %d\n", filesize);

            while(((bytes_sent = sendfile(peer_socket_server, fd, &off, SIZE)) > 0) && (bytes_remaining > 0)){
                printf("bytes sent: %d\n", bytes_sent);
                bytes_remaining -= bytes_sent;
            }
            close(fd);
        }
        fclose(fp1);
        close(peer_socket_server);
    }
}

【问题讨论】:

  • 快速浏览一下,尝试添加一些错误检查。我没有看到任何。如果recv 返回零,你会得到一个无限循环。
  • @user14063792468 我检查了返回值,在 for 循环的第二个循环中,它只接收 92 个字节而不是 600 个字节,然后 newfilesize 的 recv 返回 0。
  • 从使用调试器开始。它会立即告诉您触发 seg 错误的确切代码行,这是您应该已经完成​​并且应该在问题中发布的最小调试。也可以使用调试器检查代码在段错误时和导致段错误时的状态。
  • 问题已解决。问题是我必须在 for 循环中移动 off_t off = 0; 以在每个文件之后将其重置为 0。

标签: c sockets tcp


【解决方案1】:

问题是我必须在 for 循环中移动 off_t off = 0; 以在每个 sendfile 之后将其重置为 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 2019-04-15
    • 2016-03-20
    • 2019-07-07
    • 2021-11-27
    • 2018-03-22
    • 1970-01-01
    相关资源
    最近更新 更多