我目前正在完成我的计算机科学学士学位的最后一年作业,其中之一是使用 POSIX 线程进行并发。分配的是一个非常简单的 http 服务器,它在单独的线程中处理 http 请求并返回简单的 html 文件。在线程函数结束时释放和取消字符缓冲区时,我遇到了一些信号中止错误。我在 X-Code 中工作,当我在方案中启用 Guard Malloc 时,它工作得很好。此外,如果我删除对 free() 的调用并且取消该程序也可以正常运行。我假设后者正在消耗先前线程中使用的内存,而不是为其他进程释放它,因此不是一个好的解决方案,对吗?我不了解 Guard Malloc,但我将提交一个原始的 .cpp 文件以在 Lecturer 上进行编译
下面是完整的代码。任何你愿意扔给我的评论、风格批评或任何类型的智慧珍珠都会受到深深的赞赏。
崩溃的输入是来自这个随机网站的 .html 主页 - http://www.budgie-info.com/
提前谢谢了。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
// Define the port number to identify this process
#define MYPORT 3490
typedef struct socket_fd {
unsigned fd;
} sock_fd;
void *request(void *fd);
int main() {
int s;
//unsigned fd;
struct sockaddr_in my_addr;
pthread_t t;
int retval;
sock_fd *s_fd;
// Construct address information
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(my_addr.sin_zero, '\0', sizeof(my_addr.sin_zero) );
// Create a socket and bind it the port MYPORT
s=socket(PF_INET,SOCK_STREAM, 0);
int yes = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
retval = bind(s, (struct sockaddr *)&my_addr, sizeof(my_addr));
if( retval != 0) {
fputs ("bind() failed.",stderr);
exit (7);
}
printf("%d\n", my_addr.sin_port);
retval = listen(s,10);
if( retval != 0 ) { // Allow up to 10 incoming connections
fputs ("listen() failed.",stderr);
exit (9);
}
while(1) {
s_fd = (sock_fd*)malloc(sizeof(sock_fd));
s_fd->fd=accept(s,NULL,NULL); // wait for a request
retval = pthread_create( &t, NULL, request, s_fd);
free(s_fd);
s_fd = NULL;
if(retval != 0) {
printf("pthread_create() failed. error %d\n", retval);
}
}
}
void *request(void *s_fd) {
int retval;
char data[65536];
char header[]="HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
char header_gif[]="HTTP/1.1 200 OK\r\nContent-Type: image/gif\r\n\r\n";
char header_jpeg[]="HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\n\r\n";
char header_png[]="HTTP/1.1 200 OK\r\nContent-Type: image/png\r\n\r\n";
int header_len;
char *send_buffer;
char *temp_buffer;
char filename[256];
char filename_parsed[256];
FILE *f;
sock_fd *fd_t = (sock_fd*)s_fd;
unsigned fd = fd_t->fd;
int cnt = 0;
do {
retval=(int)recv(fd,data,65536,0); // recieve the request using fd
++cnt;
} while(retval == 65536);
if(retval < 0) {
fputs ("recv() failed.\n",stderr);
return NULL;
}
data[retval]='\0'; // NUL terminate it
retval = sscanf((char *)data,"GET /%s ",filename); // get the name of the file
if(retval != 1) {
fputs ("sscanf() failed.\n",stderr);
return NULL;
}
if(strlen(filename) > 256) {
fputs ("Filename overflow.\n",stderr);
return NULL;
}
// parse uml spaces out of filenames
int j = 0;
for(int i = 0; filename[i]!='\0'; ++i) {
if(filename[i] == '%') {
filename_parsed[j] = ' ';
i+=2;
} else {
filename_parsed[j] = filename[i];
}
++j;
}
filename_parsed[j] = '\0';
//print received header
printf("Receiving:\n %s\n", data);
//print requested filename
printf("\n\n-------------filename = %s|\n\n", filename_parsed);
if( (f=fopen(filename_parsed,"rb")) == NULL ) { // open the file (might be binary)
fputs ("fopen() failed.\n",stderr);
return NULL;
}
// obtain file size:
size_t lSize;
fseek (f , 0 , SEEK_END);
lSize = ftell (f);
rewind (f);
// pre calculate length of filename
int len = (int)strlen(filename_parsed);
// identify appropriate header, alocate required memory and copy the header into the buffer
if(0 == strcmp(filename_parsed + len - 4, ".gif")) {
header_len = (int)strlen(header_gif);
printf("\n\n\n\n\nG I F\n\n\n\n");
send_buffer = (char*) malloc ( sizeof(char)*((lSize+(size_t)header_len)+14) ); // WARNING: hardcoded margin for header size differences
memcpy(send_buffer, header_gif, header_len);
} else if(0 == strcmp(filename_parsed + len - 5, ".jpeg")) {
printf("\n\n\n\n\nJ P E G\n\n\n\n");
header_len = (int)strlen(header_jpeg);
send_buffer = (char*) malloc ( sizeof(char)*((lSize+(size_t)header_len)+14) ); // WARNING: hardcoded margin for header size differences
memcpy(send_buffer, header_jpeg, header_len);
} else if(0 == strcmp(filename_parsed + len - 4, ".png")) {
header_len = (int)strlen(header_png);
printf("\n\n\n\n\nP N G \n\n\n\n");
send_buffer = (char*) malloc ( sizeof(char)*((lSize+(size_t)header_len)+14) ); // WARNING: hardcoded margin for header size differences
memcpy(send_buffer, header_png, header_len);
} else {
header_len = (int)strlen(header);
send_buffer = (char*) malloc ( sizeof(char)*((lSize+(size_t)header_len)+14) ); // WARNING: hardcoded margin for header size differences
memcpy(send_buffer, header, header_len);
}
// allocate memory to contain the whole file:
temp_buffer = (char*) malloc (sizeof(char)*(lSize+10)); // WARNING: hardcoded margin for header size differences
if (temp_buffer == NULL) {
fputs ("malloc() failed.\n",stderr);
return NULL;
}
// copy the file into the buffer:
retval = (int)fread (temp_buffer,1,lSize,f);
if (retval != lSize) {
fputs ("fread() failed.\n",stderr);
return NULL;
}
memcpy(send_buffer + header_len, temp_buffer, retval);
//print packet being sent
printf("Sending:\n%s\n", send_buffer);
memcpy(send_buffer + retval, "\r\n", 4);
// send packet
retval = (int)send(fd,send_buffer,retval,0);
if(retval < 0) {
fputs ("send() failed.\n",stderr);
return NULL;
}
free(temp_buffer); // The section of memory management causes SIGABRT errors everytime i run, commenting them out made it run smoothly.
temp_buffer = NULL; // Is the closing of this function tidying up for me or is it leaving a memory leak trail?
free(send_buffer); // Is it the multi threading that is making memory management buggy?
send_buffer = NULL;
fclose(f);
f = NULL;
close(fd); // close the socket
return NULL;
}