sendto 在发送数据包时创建分段错误
sendto creating a segmentation fault when sending a packet
我正在尝试通过 UDP 发送数据包,但是我在第 198 行遇到段错误:
sendto(socketfd, buffer_str, total_len, 0, res->ai_addr, res->ai_addrlen);
而且我不太确定是什么原因造成的。我通过 GDB 运行 程序,none 的参数似乎有任何问题。我要发送的文件只是一个简单的 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, 0, sizeof(hints));
memset(serverAddr, 0, 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, 0, res->ai_addr, res->ai_addrlen);
char buf[1000];
int length = recvfrom(socketfd, buf, 1000, 0, (struct sockaddr *)&serverAddr, &addr_size);
gettimeofday(&post_time, NULL);
buf[length] = '[=11=]';
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, 0, SEEK_END);
int fileLength = ftell(file);
fseek(file, 0, 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, "%d", 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, "%d", 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, buffer_str, total_len, 0, res->ai_addr, 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, 0, (struct sockaddr *)&serverAddr, &addr_size);
这是因为传递的是指针serverAddr
的地址,而不是指针的值:
int length = recvfrom(socketfd, buf, 1000, 0, (struct sockaddr *)serverAddr, &addr_size);
您可能会看到该程序现在由于另一个原因而出现段错误:对于少于两个片段的短文件,缓冲区处理失败,因为 curr->next
未初始化。
我正在尝试通过 UDP 发送数据包,但是我在第 198 行遇到段错误:
sendto(socketfd, buffer_str, total_len, 0, res->ai_addr, res->ai_addrlen);
而且我不太确定是什么原因造成的。我通过 GDB 运行 程序,none 的参数似乎有任何问题。我要发送的文件只是一个简单的 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, 0, sizeof(hints));
memset(serverAddr, 0, 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, 0, res->ai_addr, res->ai_addrlen);
char buf[1000];
int length = recvfrom(socketfd, buf, 1000, 0, (struct sockaddr *)&serverAddr, &addr_size);
gettimeofday(&post_time, NULL);
buf[length] = '[=11=]';
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, 0, SEEK_END);
int fileLength = ftell(file);
fseek(file, 0, 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, "%d", 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, "%d", 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, buffer_str, total_len, 0, res->ai_addr, 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, 0, (struct sockaddr *)&serverAddr, &addr_size);
这是因为传递的是指针serverAddr
的地址,而不是指针的值:
int length = recvfrom(socketfd, buf, 1000, 0, (struct sockaddr *)serverAddr, &addr_size);
您可能会看到该程序现在由于另一个原因而出现段错误:对于少于两个片段的短文件,缓冲区处理失败,因为 curr->next
未初始化。