微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sendto在发送数据包时创建分段错误

如何解决sendto在发送数据包时创建分段错误

我正在尝试通过UDP发送数据包,但是在198行出现了段错误

sendto(socketfd,buffer_str,total_len,res->ai_addr,res->ai_addrlen);

我不太确定是什么原因造成的。我已经通过GDB运行了该程序,并且所有参数似乎都没有问题。我尝试发送的文件只是一个简单的txt文件,其中包含文本“ Lorem ipsum dolor sit amet”。

第76行的第一个sendto可以正常工作,第78行的recv也可以。当我尝试用类似76的代码替换198上的sendto时,我得到了相同的段错误

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>

struct packet {
    unsigned int total_frag;
    unsigned int frag_no;
    unsigned int size;
    char* filename;
    char filedata[1000];
};

struct node {
    struct node* next;
    struct packet data;
};

struct list {
    struct node* head;
};

int main(int argc,char *argv[]) {
    printf("ftp <file name>\n");
    
    struct sockaddr_storage their_addr;
    socklen_t addr_size = sizeof(their_addr);
    struct addrinfo hints,*res;
    char* port = "5050";//argv[2];
    struct sockaddr_in *serverAddr;
    serverAddr = malloc(sizeof(struct sockaddr_in));
    memset(&hints,sizeof(hints));
    memset(serverAddr,sizeof(*serverAddr));
    serverAddr->sin_family = AF_INET;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_addr = (struct sockaddr *) serverAddr;

    getaddrinfo("ug168.eecg.utoronto.ca"/*argv[1]*/,port,&hints,&res);
    int socketfd = socket(PF_INET,SOCK_DGRAM,0);
    char fileName[100];
    scanf("%s",fileName);
    int fd = open(fileName,O_RDWR);
    if(fd == -1) {
        return 0;
    }

    struct timeval pre_time,post_time;
    gettimeofday(&pre_time,NULL);
    sendto(socketfd,(char*)"ftp",3,res->ai_addrlen);
    char buf[1000];
    int length = recvfrom(socketfd,buf,1000,(struct sockaddr *)&serverAddr,&addr_size);
    gettimeofday(&post_time,NULL);

    buf[length] = '\0';
    if(strcmp("yes",buf) == 0) {
        printf("A file transfer can start\n");
    }
    printf("seconds : %ld\nmicro seconds : %ld\n",post_time.tv_sec - pre_time.tv_sec,post_time.tv_usec - pre_time.tv_usec);

    FILE *file;
    file = fopen(fileName,"rb"); //rb = read as binary
    fseek(file,SEEK_END);
    int fileLength = ftell(file);
    fseek(file,SEEK_SET);

    char buffer[fileLength];
    fread(buffer,fileLength,1,file);
    fclose(file);
    int frag_total = fileLength / 1000;
    if(fileLength % 1000 != 0) {
        frag_totaL++;
    }

    struct list packet_list;
    packet_list.head = malloc(sizeof(struct node));
    struct node* curr = packet_list.head;
    for(int i = 0; i < frag_total; i++) {
        curr->data.total_frag = frag_total;
        curr->data.frag_no = i + 1;
        if(i == frag_total - 1) {
            curr->data.size = fileLength % 1000;
        } else {
            curr->data.size = 1000;
        }
        curr->data.filename = malloc(sizeof(char) * (strlen(fileName) + 1));
        strcpy(curr->data.filename,fileName);
        if(i == frag_total - 1) {
            //copy data equal to remainder
            for(int j = 0; j < fileLength % 1000; j++) {
                curr->data.filedata[j] = buffer[1000 * i + j];
            }
        } else {
            //copy 1000 bytes
            for(int j = 0; j < 1000; j++) {
                curr->data.filedata[j] = buffer[1000 * i + j];
            }
        }
        if(i < frag_total - 1) {
            curr->next = malloc(sizeof(struct node));
            curr = curr->next;
        }
    }

    curr = packet_list.head;
    while(curr != NULL) {
        int j = curr->data.total_frag;
        int frag_total_len = 0;
        while(j != 0) {
            j /= 10;
            frag_total_len++;
        }
        j = curr->data.frag_no;
        int frag_no_len = 0;
        while(j != 0) {
            j /= 10;
            frag_no_len++;
        }
        j = curr->data.size;
        int size_len = 0;
        while(j != 0) {
            j /= 10;
            size_len++;
        }
        int name_len = strlen(curr->data.filename);

        int total_len = frag_total_len + frag_no_len + size_len + name_len + 4 + curr->data.size; //4 bc 4 colons

        char buffer_str[total_len];
        j = 0;

        char strbuf[total_len];

        sprintf(strbuf,"%d",curr->data.total_frag);
        for(int k = j; k < j + frag_total_len; k++) {
           buffer_str[k] = strbuf[k-j];
        }
        j += frag_total_len;
        buffer_str[j] = ':';
        j++;

        sprintf(strbuf,curr->data.frag_no);
        for(int k = j; k < j + frag_no_len; k++) {
           buffer_str[k] = strbuf[k-j];
        }
        j += frag_no_len;
        buffer_str[j] = ':';
        j++;

        sprintf(strbuf,curr->data.size);
        for(int k = j; k < j + size_len; k++) {
           buffer_str[k] = strbuf[k-j];
        }
        j += size_len;
        buffer_str[j] = ':';
        j++;

        for(int k = 0 ; k < name_len; k++,j++) {
            buffer_str[j] = curr->data.filename[k];
        }

        buffer_str[j] = ':';
        j++;
        for(int k = 0; k < curr->data.size; k++,j++) {
            buffer_str[j] = curr->data.filedata[k];
        }

        sendto(socketfd,res->ai_addrlen);
        curr = curr->next;
    }
    return 0;
}

我不确定是什么原因造成的

解决方法

原始发布的代码省略了对getaddrinfo()的错误检查,这将返回错误代码,而res保持不变;导致在调用sendto()时取消引用未初始化的指针;修订示例:

int rv = getaddrinfo("ug168.eecg.utoronto.ca"/*argv[1]*/,port,&hints,&res);
if (rv) {
    fprintf(stderr,"getaddrinfo error,rv %d\n",rv);
    return (1);
}
,

本地变量res被调用覆盖

int length = recvfrom(socketfd,buf,1000,(struct sockaddr *)&serverAddr,&addr_size);

这是因为传递了指针serverAddr的地址而不是指针的值:

int length = recvfrom(socketfd,(struct sockaddr *)serverAddr,&addr_size);

您可能会发现该程序现在由于另一个原因而发生段错误:对于少于两个片段的短文件,缓冲区处理失败,因为curr->next未初始化。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。