我正在为一个类编写一个C HTTP服务器。我有一个粗略的实施工作,但我坚持这个问题。我试图多线程化从浏览器发送的GET请求,但服务器只是在~10个请求后关闭连接。
以下是代码:
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define SERVPORT 5004
#define BUFSIZE 4096
#define MAXCONNECT 3
#define MAX_THREADS 8
struct data
{
int i;
};
void * clientHandler(void *info);
void sendError(char *msg);
char * getDate();
int sendall(int send_socket, char *buf, int *len);
int parseSrc(char src[]);
char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen);
char date[100];
char http200[50] = "HTTP/1.1 200 OK\n";
char http400[50] = "HTTP/1.1 400 Bad Request\n";
char http404[50] = "HTTP/1.1 404 Not Found\n";
int main()
{
printf("Starting server..\n");
int servSock, clntSock, fd;
struct sockaddr_in server, client;
unsigned int len, clntSize;
fd_set master;
fd_set read_fds;
int fdmax;
int i;
if( (servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
sendError("socket");
FD_ZERO(&master);
FD_ZERO(&read_fds);
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(SERVPORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
for(i=0; i<=10; i++)
{
printf("Trying port %d...\n", (ntohs(server.sin_port) + i));
if( bind(servSock, (struct sockaddr *)&server, sizeof(server)) == -1)
server.sin_port = htons(SERVPORT + i);
else if(i < 10)
break; //socket connected succesfully
else
sendError("bind");
}
printf("Successfully bound to port %d!\n", ntohs(server.sin_port));
if( listen(servSock, MAXCONNECT) == -1)
sendError("listen");
printf("Listening...\n");
FD_SET(servSock, &master);
fdmax = servSock;
pthread_t threads[MAX_THREADS];
while(1)
{
read_fds = master;
int num_threads = 0;
if( select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1)
sendError("select");
for(i = 0; i <= fdmax; i++)
{
if(FD_ISSET(i, &read_fds))
{
if(i == servSock)
{
clntSize = sizeof(client);
if( (clntSock = accept(servSock, (struct sockaddr *)&client, &clntSize)) == -1)
sendError("accept");
FD_SET(clntSock, &master);
if(clntSock > fdmax)
fdmax = clntSock;
char s[50];
printf("Connected to %s\n", get_ip_str((struct sockaddr *)&client, s, sizeof(s)));
}
else
{
//clientHandler(i);
struct data *info;
info = malloc(sizeof(struct data));
info->i = i;
if(pthread_create(&threads[i], NULL, (void *)clientHandler, (void *)info))
sendError("pthread");
num_threads++;
}
}
}
if(num_threads > MAX_THREADS)
{
num_threads = 0;
pthread_join(threads[num_threads], NULL);
}
}
for(i = 0; i < MAX_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
}
void *clientHandler(void *info)
{
struct data *myinfo = (struct data*) info;
int clntSock = myinfo->i;
char buf[BUFSIZE];
int recd;
if( (recd = recv(clntSock, buf, BUFSIZE, 0)) == -1)
sendError("recieve1");
while(recd > 0)
{
char cmd[5] = "/0";
char src[100] = "/0";
char prt[100] = "/0";
memset(&cmd, 0, sizeof(cmd));
memset(&src, 0, sizeof(src));
memset(&prt, 0, sizeof(prt));
sscanf(buf, "%4s%99s%99s", cmd, src, prt);
char cmdget[5] = "GET";
if(strcmp(cmd, cmdget) == 0) //GET command
{
int len;
if(src[0] == '/')
memmove(src, src+1, strlen(src));
if(strlen(src) == 0)
strcpy(src, "index.html");
FILE *fp;
fp = fopen(src, "r");
if(fp == NULL)
{
len = strlen(http404);
if(sendall(clntSock, http404, &len) == -1)
sendError("send 404");
break;
}
struct stat buf;
fstat(fileno(fp), &buf);
char contLen[50] = "Content-Length: ";
sprintf(contLen, "%s%d\n", contLen, (int)buf.st_size);
char contType[100] = "Content-Type: ";
char *tempType;
tempType = strrchr(src, '.');
if(strcmp(tempType, ".html") == 0) //.html
strcat(contType, "text/html\n");
else if(strcmp(tempType, ".txt") == 0) //.txt
strcat(contType, "text/txt\n");
else if(strcmp(tempType, ".css") == 0) //.css
strcat(contType, "text/css\n");
else if(strcmp(tempType, ".jpg") == 0) //.jpg
strcat(contType, "image/jpg\n");
else if(strcmp(tempType, ".png") == 0) //.png
strcat(contType, "image/png\n");
else if(strcmp(tempType, ".gif") == 0) //.gif
strcat(contType, "image/gif\n");
else if(strcmp(tempType, ".js") == 0) //.js
strcat(contType, "application/javascript\n");
else
{
char fileErrorTemp[50] = "Unknown filetype: ";
strcat(fileErrorTemp, tempType);
sendError(fileErrorTemp);
}
char tempDate[100] = "";
strcpy(tempDate, getDate());
char tempMsg[500] = "";
strcat(tempMsg, http200);
strcat(tempMsg, tempDate);
strcat(tempMsg, contType);
strcat(tempMsg, contLen);
strcat(tempMsg, "\n");
len = strlen(tempMsg);
if( sendall(clntSock, tempMsg, &len) == -1)
sendError("send 200");
printf("Sent client: %s @ %s", http200, tempDate);
printf(" Sending %s\n", src);
if( sendfile(fp, clntSock) == -1)
sendError("file send");
}
else //Unknown or bad command
{
int http400len = strlen(http400);
if( send(clntSock, http400, strlen(http400), 0) == -1)
sendError("send 400");
}
printf("Waiting to receive...\n");
if( (recd = recv(clntSock,buf, BUFSIZE, 0)) == -1)
sendError("recieve1");
//printf("%d\n", recd);
}
close(clntSock);
return;
}
void sendError(char *msg)
{
perror(msg);
exit(-1);
}
char * getDate() //return date in "Date: Tue, 16 Feb 2010 19:21:24 GMT" format
{
memset(&date, 0, sizeof(date));
strcpy(date, "Date: ");
time_t rawtime = time(0);
struct tm * info;
time(&rawtime);
info = gmtime(&rawtime);
char wday[5];
char mon[5];
switch(info->tm_wday){
case 0: strcpy(wday, "Mon");
case 1: strcpy(wday, "Tue");
case 2: strcpy(wday, "Wed");
case 3: strcpy(wday, "Thu");
case 4: strcpy(wday, "Fri");
case 5: strcpy(wday, "Sat");
case 6: strcpy(wday, "Sun");
}
switch(info->tm_mon){
case 0: strcpy(mon, "Jan");
case 1: strcpy(mon, "Feb");
case 2: strcpy(mon, "Mar");
case 3: strcpy(mon, "Apr");
case 4: strcpy(mon, "May");
case 5: strcpy(mon, "Jun");
case 6: strcpy(mon, "Jul");
case 7: strcpy(mon, "Aug");
case 8: strcpy(mon, "Sep");
case 9: strcpy(mon, "Oct");
case 10: strcpy(mon, "Nov");
case 11: strcpy(mon, "Dec");
}
char temp[5];
strcat(date, wday);
strcat(date, ", ");
sprintf(temp, "%2d", info->tm_mday);
strcat(date, temp);
strcat(date, " ");
strcat(date, mon);
sprintf(temp, " %4d ", (info->tm_year + 1900));
strcat(date, temp);
sprintf(temp, "%d:", info->tm_hour);
strcat(date, temp);
sprintf(temp, "%.2d:", info->tm_min);
strcat(date, temp);
sprintf(temp, "%.2d", info->tm_sec);
strcat(date, temp);
strcat(date, " UTC\n");
return date;
}
int sendall(int send_socket, char *buf, int *len)
{
int total = 0;
int bytesleft = *len;
int n;
while(total < *len)
{
n = send(send_socket, (buf + total), bytesleft, 0);
if(n == -1)
break;
total += n;
bytesleft -= n;
}
*len = total;
if(n==-1)
return -1;
else
return 0;
}
int sendfile(FILE* fp, int clntSock)
{
while(1)
{
unsigned char buff[256]={0};
int nread = fread(buff, 1, 256, fp);
if(nread > 0)
write(clntSock, buff, nread);
if(nread < 256)
{
if(feof(fp))
break; //eof
if(ferror(fp))
return -1;
}
}
return 0;
}
int parseSrc(char src[])
{
printf("%s", src);
if(src[0] == '/')
{
printf("SLASH");
src++;
return 2;
}
printf("%s", src);
return 1;
}
char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
{
switch(sa->sa_family)
{
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen);
break;
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen);
break;
default:
strncpy(s, "Unknown AF", maxlen);
return NULL;
}
return s;
}
我真的被卡住了。任何帮助将不胜感激!