C HTTP Server上的多线程错误

时间:2015-10-20 23:46:11

标签: c multithreading http server

我正在为一个类编写一个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;
}

我真的被卡住了。任何帮助将不胜感激!

0 个答案:

没有答案