网络服务器有时无法发送所有图像
webserver sometimes fails to send all images
所以我已经在 Web 服务器上工作了几个月,但我无法解决这个问题。这个问题是大多数时候,当服务器尝试将数据发送到 Web 客户端时,一些图像不会发送 across/don 不会加载。我已经研究了一段时间,但没有找到解决方案。我知道它有很多代码,但这是让它正常工作的最后一件事。
代码如下:
//this is where you enter the default file directories
char *defaultDir1 = "/enter/website/path/here";
char *defaultDir2 = "/enter/server/path/here";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
struct sockaddr_in sockaddr;
char webFileDir[9000];
char servFileDir[9000];
#define THREAD_POOL_SIZE 200
#define BACKLOG 200
pthread_t thread_pool[THREAD_POOL_SIZE];
//creates a lock and unlock system for enqueue and dequeue
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//creates a sleep timer for the threads/does something until given a signal or condition.
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
struct node {
int *client_socket;
struct node *next;
};
typedef struct node node_t;
node_t *head = NULL;
node_t *tail = NULL;
void enqueue(int *client_socket) {
node_t *newnode = malloc(sizeof(node_t)); //create node
newnode->client_socket = client_socket; //assign client socket
newnode->next = NULL; //add node to the end of the list
if (tail == NULL) { //checks if there is nothing on the tail and if so adds a head
head = newnode;
} else {
//if there is a tail then add a new node onto the tail
tail->next = newnode;
}
tail = newnode;
//this all basically creates a new node then moves it over over and over again until stopped
}
int *dequeue() {
if (head == NULL) {
//if the head is empty or nothing has been enqueued then return null
return NULL;
}
if (head != NULL) { //else...
int *result = head->client_socket;
node_t *temp = head;
head = head->next;
if (head == NULL) {tail = NULL;}
free(temp);
return result;
}
//this function removes everything off of the queue
return 0;
}
int *handleClient(int *pClientSock) {
FILE *fpointer;
char *findExtention;
char *clientIP;
char *endDir;
int freadErr;
int fsize;
int bin;
int readSock;
char recvLine[2];
char fileDir[9000];
char recvLineGET1[70];
char recvLineGET[60];
char httpResponseReport[1000];
char *fileLine;
char httpResponse[1000];
char *endOfPost;
char *splitPost;
char *postContentLength;
char *finalPostLength;
char tempPost[2000];
int contentLen;
char *refindBody;
char finalBody[100000];
char fullResp[100000];
char *sendFileDirectory;
int checkSend;
char *startDir;
char *getEnd;
int responseCode = 200;
memset(fileDir, 0, sizeof(fileDir));
memset(recvLineGET, 0, sizeof(recvLineGET));
//get client ip
int acceptSock = *pClientSock;
socklen_t addrSize = sizeof(struct sockaddr_in);
getpeername(acceptSock, (struct sockaddr *)&sockaddr, &addrSize);
clientIP = inet_ntoa(sockaddr.sin_addr);
fullResp[0] = '[=10=]';
//handles reading client http request
while (1) {
if ((readSock = read(acceptSock, recvLine, 1)) != 1) {
perror("error reading from socket");
send(acceptSock, "HTTP/1.1 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(recvLine, 0, sizeof(recvLine));
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
recvLine[1] = '[=10=]';
strcat(fullResp, recvLine);
printf("%s", recvLine);
if ((endOfPost = strstr(fullResp, "\n")) != NULL) {
break;
} else if (readSock < 0) {
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
memset(recvLine, 0, sizeof(recvLine));
}
printf("fullResp: %s\n", fullResp);
strcpy(fileDir, webFileDir);
//
//POSSIBLE ERROR HERE
//
if ((getEnd = strstr(fullResp, "HTTP")) == NULL) {
memset(fullResp, 0, sizeof(fullResp));
send(acceptSock, "HTTP/1.0 400\r\n\r\n", 16, MSG_NOSIGNAL);
close(acceptSock);
return 0;
}
strcpy(getEnd, "");
if ((startDir = strchr(fullResp, '/')) == NULL) {
perror("this shouldnt happen .-.");
printf("startDir: %s\n", startDir);
send(acceptSock, "HTTP/1.0 400\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
//handles the file retrieving
if ((endDir = strchr(startDir, ' ')) == NULL) {
perror("endDir error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fileDir, 0, sizeof(fileDir));
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
strcpy(endDir, "");
//checks for requested directory
if (strcmp(startDir, "/") == 0) {
findExtention = ".html";
strcpy(fileDir, webFileDir);
strcat(fileDir, "index.html");
responseCode = 200;
} else {
if ((findExtention = strchr(startDir, '.')) == NULL) {
perror("invalid webpage");
findExtention = ".html";
strcpy(fileDir, servFileDir);
strcat(fileDir, "err404.html");
responseCode = 404;
}
strcat(fileDir, startDir);
}
//
//START POSSIBLE ERROR
//
if ((fpointer = fopen(fileDir, "rb")) != NULL) {
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
} else if (strcmp(startDir-1, "/favicon.ico") == 0 && access(fileDir, F_OK) != 0) {
strcpy(fileDir, servFileDir);
strcat(fileDir, "favicon.ico");
if (access(fileDir, F_OK) != 0) {
printf("\n\n\nERROR: please do not delete the default favicon.ico file. the program will not work properly if it is deleted\n\n\n");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
exit(1);
}
if ((fpointer = fopen(fileDir, "rb")) == NULL) {
perror("fopen error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
} else if (access(fileDir, F_OK) != 0) {
perror("webpage doesnt exist");
findExtention = ".html";
strcpy(fileDir, servFileDir);
strcat(fileDir, "err404.html");
responseCode = 404;
if ((fpointer = fopen(fileDir, "r")) == NULL) {
perror("fopen error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
}
//
//END POSSIBLE ERROR
//
fclose(fpointer);
//sets the server http response
if ((strcmp(findExtention, ".jpeg")) == 0 || (strcmp(findExtention, ".jpg")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".png")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nnContent-Type: image/png\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".ico")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: image/x-icon\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".mp3")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: audio/mpeg\r\nContent-length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".html")) == 0) {
bin = 0;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", responseCode, fsize);
} else {
strcpy(fileDir, "err404.html");
fpointer = fopen(fileDir, "r");
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
fclose(fpointer);
bin = 0;
sprintf(httpResponse, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", fsize);
}
strcpy(httpResponseReport, httpResponse);
if (readSock < 0) {
perror("readsock is less than 0");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//checks if i need to read plaintext or binary
if (bin == 0) {
fpointer = fopen(fileDir, "r");
} else if (bin == 1) {
fpointer = fopen(fileDir, "rb");
}
if (fpointer == NULL) {
perror("file open error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//sends server http response to client
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
fclose(fpointer);
//checks if i need to read plaintext or binary (again)
if (bin == 0) {
fpointer = fopen(fileDir, "r");
} else if (bin == 1) {
fpointer = fopen(fileDir, "rb");
}
if (fpointer == NULL) {
perror("fopen error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponse, 0, sizeof(httpResponse));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
close(acceptSock);
return 0;
}
fileLine = malloc(fsize * sizeof(char));
while ((freadErr = fread(fileLine, fsize, fsize, fpointer)) > 0);
if (feof(fpointer) < 0) {
perror("fread error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//set 5 second socket timeout
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (setsockopt(acceptSock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
perror("setsockopt error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
close(acceptSock);
return 0;
}
//
//POSSIBLE ERROR HERE
//
while (1) {
if ((checkSend = send(acceptSock, httpResponse,
strlen(httpResponse), MSG_NOSIGNAL)) == -1) {
break;
}
//send full response
if ((checkSend = send(acceptSock, fileLine, fsize,
MSG_NOSIGNAL)) == -1) {
break;
}
sleep(1);
}
//
//END POSSIBLE ERROR
//
memset(httpResponse, 0, sizeof(httpResponse));
memset(fullResp, 0, sizeof(fullResp));
fclose(fpointer);
close(acceptSock);
free(fileLine);
//handles the clearing of variables and logs client ip and requested directory
printf("\nclient with the ip: %s has requested %s.\n", clientIP, fileDir);
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
return 0;
}
//assign work to each thread
void *giveThreadWork() {
while (1) {
int *pclient;
pthread_mutex_lock(&mutex);
//makes thread wait until signaled
if ((pclient = dequeue()) == NULL) {
pthread_cond_wait(&condition_var, &mutex);
pclient = dequeue();
}
pthread_mutex_unlock(&mutex);
//i dont think i need this rn. might need it later so dont delete
if (pclient != NULL) {
handleClient(pclient);
} else {
//printf("\n\n\n\n\n no more listener \n\n\n\n\n");
}
}
}
int main() {
int clientSock;
int readSock;
int sock;
int portNum;
int defaultOrNo;
int openDir;
char readTemp[1];
printf("\n\n\nWeb Server\n\n\n");
printf("would you like to use default directories (1 = yes, 0 = no): ");
scanf("%d", &defaultOrNo);
if (defaultOrNo == 0) {
printf("enter the directory of the files to be served (with '/' at the end): ");
scanf("%s", webFileDir);
printf("enter the directory of the web server folder (with '/' at the end): ");
scanf("%s", servFileDir);
} else if (defaultOrNo == 1) {
strcpy(webFileDir, defaultDir1);
strcpy(servFileDir, defaultDir2);
}
printf("what port would you like to host the site on?: ");
scanf("%d", &portNum);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("sock error");
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockaddr.sin_port = htons(portNum);
if ((bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) < 0) {
perror("bind error");
exit(1);
}
printf("socket bind success\n");
//create all the threads for the thread pool
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&thread_pool[i], NULL, giveThreadWork, NULL);
}
printf("created thread pool of size %d successfully\n", THREAD_POOLSIZE);
if ((listen(sock, BACKLOG)) < 0) {
perror("listen error");
}
printf("listen success\n");
while (1) {
//checks for client connection
if ((clientSock = accept(sock, NULL, NULL)) < 0) {
perror("accept error");
//oh no too bad
} else {
int *pclient = &clientSock;
pthread_mutex_lock(&mutex);
enqueue(pclient);
//sends a signal to wait until needed
pthread_cond_signal(&condition_var);
pthread_mutex_unlock(&mutex);
}
}
return 0;
}
最新编辑:我没有收到来自客户的一些请求,或者我没有正确发送它们。我会在找出问题后编辑问题。
我已经标记了我认为主要问题是使用注释的地方,这样你们调试起来会更容易。祝你好运,非常感谢任何能解决这个问题的人!!!
ps:特别感谢@AndreasWenzel 的所有帮助
您的链表应包含必须处理的 HTTP 请求的所有套接字文件描述符的列表。因此,链表中的每个节点都应该包含一个文件描述符。
您目前正在做的是创建一个链表,其中每个节点都包含一个指向文件描述符的指针。但是,每个节点都指向相同的文件描述符变量(指向函数 main
中的 clientSock
)。因此,您的链表实际上只存储了一个文件描述符,每当有新的 HTTP 请求到达时,它就会不断被覆盖。
因此,您应该更改链表节点的定义,以便每个节点都包含自己的文件描述符(而不是指向文件描述符的指针):
struct node {
int client_socket;
struct node *next;
};
此外,您应该更改函数 enqueue
和 handleClient
的函数原型以接受 int
参数而不是 int *
和 dequeue
应该 return 一个 int
而不是 int *
。当列表为空时,函数 dequeue
应该 return -1
。应该使用这个值,因为它不能表示有效的文件描述符。
当然,您还应该相应地调整调用这些函数的代码。
所以我已经在 Web 服务器上工作了几个月,但我无法解决这个问题。这个问题是大多数时候,当服务器尝试将数据发送到 Web 客户端时,一些图像不会发送 across/don 不会加载。我已经研究了一段时间,但没有找到解决方案。我知道它有很多代码,但这是让它正常工作的最后一件事。
代码如下:
//this is where you enter the default file directories
char *defaultDir1 = "/enter/website/path/here";
char *defaultDir2 = "/enter/server/path/here";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
struct sockaddr_in sockaddr;
char webFileDir[9000];
char servFileDir[9000];
#define THREAD_POOL_SIZE 200
#define BACKLOG 200
pthread_t thread_pool[THREAD_POOL_SIZE];
//creates a lock and unlock system for enqueue and dequeue
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//creates a sleep timer for the threads/does something until given a signal or condition.
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
struct node {
int *client_socket;
struct node *next;
};
typedef struct node node_t;
node_t *head = NULL;
node_t *tail = NULL;
void enqueue(int *client_socket) {
node_t *newnode = malloc(sizeof(node_t)); //create node
newnode->client_socket = client_socket; //assign client socket
newnode->next = NULL; //add node to the end of the list
if (tail == NULL) { //checks if there is nothing on the tail and if so adds a head
head = newnode;
} else {
//if there is a tail then add a new node onto the tail
tail->next = newnode;
}
tail = newnode;
//this all basically creates a new node then moves it over over and over again until stopped
}
int *dequeue() {
if (head == NULL) {
//if the head is empty or nothing has been enqueued then return null
return NULL;
}
if (head != NULL) { //else...
int *result = head->client_socket;
node_t *temp = head;
head = head->next;
if (head == NULL) {tail = NULL;}
free(temp);
return result;
}
//this function removes everything off of the queue
return 0;
}
int *handleClient(int *pClientSock) {
FILE *fpointer;
char *findExtention;
char *clientIP;
char *endDir;
int freadErr;
int fsize;
int bin;
int readSock;
char recvLine[2];
char fileDir[9000];
char recvLineGET1[70];
char recvLineGET[60];
char httpResponseReport[1000];
char *fileLine;
char httpResponse[1000];
char *endOfPost;
char *splitPost;
char *postContentLength;
char *finalPostLength;
char tempPost[2000];
int contentLen;
char *refindBody;
char finalBody[100000];
char fullResp[100000];
char *sendFileDirectory;
int checkSend;
char *startDir;
char *getEnd;
int responseCode = 200;
memset(fileDir, 0, sizeof(fileDir));
memset(recvLineGET, 0, sizeof(recvLineGET));
//get client ip
int acceptSock = *pClientSock;
socklen_t addrSize = sizeof(struct sockaddr_in);
getpeername(acceptSock, (struct sockaddr *)&sockaddr, &addrSize);
clientIP = inet_ntoa(sockaddr.sin_addr);
fullResp[0] = '[=10=]';
//handles reading client http request
while (1) {
if ((readSock = read(acceptSock, recvLine, 1)) != 1) {
perror("error reading from socket");
send(acceptSock, "HTTP/1.1 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(recvLine, 0, sizeof(recvLine));
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
recvLine[1] = '[=10=]';
strcat(fullResp, recvLine);
printf("%s", recvLine);
if ((endOfPost = strstr(fullResp, "\n")) != NULL) {
break;
} else if (readSock < 0) {
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
memset(recvLine, 0, sizeof(recvLine));
}
printf("fullResp: %s\n", fullResp);
strcpy(fileDir, webFileDir);
//
//POSSIBLE ERROR HERE
//
if ((getEnd = strstr(fullResp, "HTTP")) == NULL) {
memset(fullResp, 0, sizeof(fullResp));
send(acceptSock, "HTTP/1.0 400\r\n\r\n", 16, MSG_NOSIGNAL);
close(acceptSock);
return 0;
}
strcpy(getEnd, "");
if ((startDir = strchr(fullResp, '/')) == NULL) {
perror("this shouldnt happen .-.");
printf("startDir: %s\n", startDir);
send(acceptSock, "HTTP/1.0 400\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
//handles the file retrieving
if ((endDir = strchr(startDir, ' ')) == NULL) {
perror("endDir error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fileDir, 0, sizeof(fileDir));
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
strcpy(endDir, "");
//checks for requested directory
if (strcmp(startDir, "/") == 0) {
findExtention = ".html";
strcpy(fileDir, webFileDir);
strcat(fileDir, "index.html");
responseCode = 200;
} else {
if ((findExtention = strchr(startDir, '.')) == NULL) {
perror("invalid webpage");
findExtention = ".html";
strcpy(fileDir, servFileDir);
strcat(fileDir, "err404.html");
responseCode = 404;
}
strcat(fileDir, startDir);
}
//
//START POSSIBLE ERROR
//
if ((fpointer = fopen(fileDir, "rb")) != NULL) {
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
} else if (strcmp(startDir-1, "/favicon.ico") == 0 && access(fileDir, F_OK) != 0) {
strcpy(fileDir, servFileDir);
strcat(fileDir, "favicon.ico");
if (access(fileDir, F_OK) != 0) {
printf("\n\n\nERROR: please do not delete the default favicon.ico file. the program will not work properly if it is deleted\n\n\n");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
exit(1);
}
if ((fpointer = fopen(fileDir, "rb")) == NULL) {
perror("fopen error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
} else if (access(fileDir, F_OK) != 0) {
perror("webpage doesnt exist");
findExtention = ".html";
strcpy(fileDir, servFileDir);
strcat(fileDir, "err404.html");
responseCode = 404;
if ((fpointer = fopen(fileDir, "r")) == NULL) {
perror("fopen error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
close(acceptSock);
return 0;
}
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
}
//
//END POSSIBLE ERROR
//
fclose(fpointer);
//sets the server http response
if ((strcmp(findExtention, ".jpeg")) == 0 || (strcmp(findExtention, ".jpg")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".png")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nnContent-Type: image/png\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".ico")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: image/x-icon\r\nContent-Length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".mp3")) == 0) {
bin = 1;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: audio/mpeg\r\nContent-length: %d\r\nContent-Transfer-Encoding: binary\r\n\r\n", responseCode, fsize);
} else if ((strcmp(findExtention, ".html")) == 0) {
bin = 0;
sprintf(httpResponse, "HTTP/1.0 %d\r\nConnection: close\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", responseCode, fsize);
} else {
strcpy(fileDir, "err404.html");
fpointer = fopen(fileDir, "r");
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
fclose(fpointer);
bin = 0;
sprintf(httpResponse, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", fsize);
}
strcpy(httpResponseReport, httpResponse);
if (readSock < 0) {
perror("readsock is less than 0");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//checks if i need to read plaintext or binary
if (bin == 0) {
fpointer = fopen(fileDir, "r");
} else if (bin == 1) {
fpointer = fopen(fileDir, "rb");
}
if (fpointer == NULL) {
perror("file open error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//sends server http response to client
fseek(fpointer, 0L, SEEK_END);
fsize = ftell(fpointer);
fclose(fpointer);
//checks if i need to read plaintext or binary (again)
if (bin == 0) {
fpointer = fopen(fileDir, "r");
} else if (bin == 1) {
fpointer = fopen(fileDir, "rb");
}
if (fpointer == NULL) {
perror("fopen error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponse, 0, sizeof(httpResponse));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
close(acceptSock);
return 0;
}
fileLine = malloc(fsize * sizeof(char));
while ((freadErr = fread(fileLine, fsize, fsize, fpointer)) > 0);
if (feof(fpointer) < 0) {
perror("fread error");
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
memset(fullResp, 0, sizeof(fullResp));
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
memset(httpResponse, 0, sizeof(httpResponse));
close(acceptSock);
return 0;
}
//set 5 second socket timeout
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (setsockopt(acceptSock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
perror("setsockopt error");
//error 500: internal server error
send(acceptSock, "HTTP/1.0 500\r\n\r\n", 16, MSG_NOSIGNAL);
close(acceptSock);
return 0;
}
//
//POSSIBLE ERROR HERE
//
while (1) {
if ((checkSend = send(acceptSock, httpResponse,
strlen(httpResponse), MSG_NOSIGNAL)) == -1) {
break;
}
//send full response
if ((checkSend = send(acceptSock, fileLine, fsize,
MSG_NOSIGNAL)) == -1) {
break;
}
sleep(1);
}
//
//END POSSIBLE ERROR
//
memset(httpResponse, 0, sizeof(httpResponse));
memset(fullResp, 0, sizeof(fullResp));
fclose(fpointer);
close(acceptSock);
free(fileLine);
//handles the clearing of variables and logs client ip and requested directory
printf("\nclient with the ip: %s has requested %s.\n", clientIP, fileDir);
memset(fileDir, 0, sizeof(fileDir));
memset(httpResponseReport, 0, sizeof(httpResponseReport));
return 0;
}
//assign work to each thread
void *giveThreadWork() {
while (1) {
int *pclient;
pthread_mutex_lock(&mutex);
//makes thread wait until signaled
if ((pclient = dequeue()) == NULL) {
pthread_cond_wait(&condition_var, &mutex);
pclient = dequeue();
}
pthread_mutex_unlock(&mutex);
//i dont think i need this rn. might need it later so dont delete
if (pclient != NULL) {
handleClient(pclient);
} else {
//printf("\n\n\n\n\n no more listener \n\n\n\n\n");
}
}
}
int main() {
int clientSock;
int readSock;
int sock;
int portNum;
int defaultOrNo;
int openDir;
char readTemp[1];
printf("\n\n\nWeb Server\n\n\n");
printf("would you like to use default directories (1 = yes, 0 = no): ");
scanf("%d", &defaultOrNo);
if (defaultOrNo == 0) {
printf("enter the directory of the files to be served (with '/' at the end): ");
scanf("%s", webFileDir);
printf("enter the directory of the web server folder (with '/' at the end): ");
scanf("%s", servFileDir);
} else if (defaultOrNo == 1) {
strcpy(webFileDir, defaultDir1);
strcpy(servFileDir, defaultDir2);
}
printf("what port would you like to host the site on?: ");
scanf("%d", &portNum);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("sock error");
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockaddr.sin_port = htons(portNum);
if ((bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) < 0) {
perror("bind error");
exit(1);
}
printf("socket bind success\n");
//create all the threads for the thread pool
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&thread_pool[i], NULL, giveThreadWork, NULL);
}
printf("created thread pool of size %d successfully\n", THREAD_POOLSIZE);
if ((listen(sock, BACKLOG)) < 0) {
perror("listen error");
}
printf("listen success\n");
while (1) {
//checks for client connection
if ((clientSock = accept(sock, NULL, NULL)) < 0) {
perror("accept error");
//oh no too bad
} else {
int *pclient = &clientSock;
pthread_mutex_lock(&mutex);
enqueue(pclient);
//sends a signal to wait until needed
pthread_cond_signal(&condition_var);
pthread_mutex_unlock(&mutex);
}
}
return 0;
}
最新编辑:我没有收到来自客户的一些请求,或者我没有正确发送它们。我会在找出问题后编辑问题。
我已经标记了我认为主要问题是使用注释的地方,这样你们调试起来会更容易。祝你好运,非常感谢任何能解决这个问题的人!!!
ps:特别感谢@AndreasWenzel 的所有帮助
您的链表应包含必须处理的 HTTP 请求的所有套接字文件描述符的列表。因此,链表中的每个节点都应该包含一个文件描述符。
您目前正在做的是创建一个链表,其中每个节点都包含一个指向文件描述符的指针。但是,每个节点都指向相同的文件描述符变量(指向函数 main
中的 clientSock
)。因此,您的链表实际上只存储了一个文件描述符,每当有新的 HTTP 请求到达时,它就会不断被覆盖。
因此,您应该更改链表节点的定义,以便每个节点都包含自己的文件描述符(而不是指向文件描述符的指针):
struct node {
int client_socket;
struct node *next;
};
此外,您应该更改函数 enqueue
和 handleClient
的函数原型以接受 int
参数而不是 int *
和 dequeue
应该 return 一个 int
而不是 int *
。当列表为空时,函数 dequeue
应该 return -1
。应该使用这个值,因为它不能表示有效的文件描述符。
当然,您还应该相应地调整调用这些函数的代码。