一个多线程web服务器实例(C,Linux,详细的web服务器原理) 转

11 篇文章 0 订阅

系统:fedora core 5
编译器:g++
实现功能:通过http协议,用浏览器查看服务器上的html,htm,jpg,jpeg,gif,png,css文件 ,或者说查看带有jpg,jpeg,gif等文件的网页,即是web~
把代码复制下来到linux里,照着后面的方法编译、运行,就可以看到一个简单的多线程服务器的效果了。

原理:
在浏览器中输入一个网址,回车之后,浏览器会向相应主机的相应端口发送一段报文,如果是http协议的(如平常看到的网页的传输协议),就会发送HTTP请求报文。

 

 

/*****************************************************************

  mymultiwebserver.c

  system:redhat linux Fedora Core 5

  enviroment:g++

  compile command:g++ -g -o mymultiwebserver -lpthread

  date:10/15/2006

  By Manio

 *****************************************************************/

#include <stdlib.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/stat.h>

#include <netinet/in.h>

#include <unistd.h>

#include <pthread.h>

#include <stdio.h>

#include <string.h>

#include <arpa/inet.h>

 

#define PORT 8848

#define BACKLOG 5

#define MAXDATASIZE 1000

#define DEBUG 1

void process_cli(int connectfd, sockaddr_in client);

int sendobj(int connectfd,char* serverfilepath);

int IsDIR(char* fpath);

int fileordirExist(char* fpath);

char* getextname(char*);

int writehead(FILE* cfp, char* extname);

void* start_routine(void* arg);

void msg404(int connectfd);

 

struct ARG {

       int connfd;

       sockaddr_in client;

       };

      

main()

{

      int listenfd, connectfd;

      pthread_t thread;         //id of thread

      ARG *arg;            //pass this var to the thread

      struct sockaddr_in server; //server's address info

      struct sockaddr_in client; //client's

      int sin_size;

     

      //create tcp socket

#ifdef DEBUG

      printf("socket.... ");

#endif

      if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

                    perror("creating socket failed.");

                    exit(1);

      }

     

      int opt = SO_REUSEADDR;

      setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

     

      bzero(&server,sizeof(server));

      server.sin_family = AF_INET;

      server.sin_port = htons(PORT);

      server.sin_addr.s_addr = htonl(INADDR_ANY);

      printf("bind.... ");

      if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {

          perror("bind error.");

          exit(1);

      }

     

      printf("listen.... ");

      if(listen(listenfd,BACKLOG) == -1) {

          perror("listen() error ");

          exit(1);

      }

 

      sin_size = sizeof(struct sockaddr_in);

      while(1)

      {

          //accept() using main thread

          printf("accepting.... ");

          if((connectfd = accept(listenfd,

                     (struct sockaddr *)&client,

                     (socklen_t*)&sin_size)) == -1) {

              printf("accept() error ");

          }

 

          arg = new ARG;

          arg->connfd = connectfd;

          memcpy((void *)&arg->client, &client, sizeof(client));

       

          //invoke start_routine to handle this thread

#ifdef DEBUG

          printf("thread_creating....");

#endif

          if(pthread_create(&thread, NULL, start_routine, (void*)arg)){

              perror("pthread_create() error");

              exit(1);

          }         

      }

      close(listenfd);     

}

 

 

//handle the request of the client

void process_cli(int connectfd, sockaddr_in client)

{

    int num;

    //char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

    char requestline[MAXDATASIZE], filepath[MAXDATASIZE], cmd[MAXDATASIZE],extname[MAXDATASIZE];

    int c;

    FILE *fp;

    FILE *cfp;

    fp = fdopen(connectfd,"r");   

   

#ifdef DEBUG

    printf("the host is:%s  ",inet_ntoa(client.sin_addr) );

#endif

    fgets(requestline,MAXDATASIZE,fp);

#ifdef DEBUG

    printf(" THE REQUEST IS :%s ",requestline);

#endif

    strcpy(filepath,"./");

    sscanf(requestline,"%s%s",cmd,filepath+2);

    strcpy(extname, getextname(filepath));

#ifdef DEBUG

    printf("cmd:%s filepath:%s extname:%s ",cmd,filepath,extname);

   

    printf("string comparing :::::::::::::start::::::::::::::: ");   

#endif

    if(strcmp(cmd,"GET") == 0){

    //the command is get

#ifdef DEBUG

        printf("cmd(%s)==GET ",cmd);

#endif

        //is this a file or dir or notexist?

        if(fileordirExist(filepath)){

        //is a file or dir or none

            //is this a dir

            if(IsDIR(filepath)){

                //is a dir

#ifdef DEBUG

                printf("%s is a DIR ",filepath);

#endif

                if( fileordirExist( strcat(filepath,"index.htm") )){

                    sendobj(connectfd,"index.htm");

                }else if(fileordirExist(strcat(filepath,"index.html"))){

                    sendobj(connectfd,"index.htm");

                }else{

                    msg404(connectfd);

                }

            }else{

                    //is a file

#ifdef DEBUG

                    printf("%s is a file",filepath);

#endif

                    sendobj(connectfd,filepath);

            }

        }else{

#ifdef DEBUG

            printf("404 ");

#endif

            msg404(connectfd);

        }

    }else{

#ifdef DEBUG

        printf("cmd(%s)!=GET ",cmd);

#endif

    }

#ifdef DEBUG

    printf(":::::::::::::end::::::::::::::: ");   

#endif

    close(connectfd);

}

//send the 404 error message to the client

void msg404(int connectfd)

{

    char* msg;

    msg  = "HTTP/1.0 404 Not Found Content-Type: text/plain 404 not found by Manio";

    send(connectfd,msg,strlen(msg),0);

}

//is the filepath a file  or directory

int fileordirExist(char* fpath)

{

    struct stat filestat;

    return (  stat(fpath,&filestat) != -1);

}

 

// is the filepath a directory

int IsDIR(char* fpath)

{

#ifdef DEBUG

    printf("IN IsDIR ");

#endif

    struct stat filestat;

    return ( stat(fpath,&filestat) != -1 && S_ISDIR(filestat.st_mode));

}

 

//send the data of the file which the client want

int sendobj(int connectfd,char* serverfilepath)

{

    FILE* sfp,*cfp;

    int c;

    sfp = fopen(serverfilepath,"r");

    cfp = fdopen(connectfd,"w");

 

    writehead(cfp,getextname(serverfilepath));

    while( (c = getc(sfp)) != EOF)putc(c,cfp);   

    fflush(cfp);

    return 0;

}

//write the packet header to the client

int writehead(FILE* cfp, char* extname)

{

#ifdef DEBUG

    printf("INWRITEHEAD:::::::extname is %s::::::: ",extname);

#endif

    char* content = "text/plain";

    if( strcmp(extname,"html") == 0 || strcmp(extname,"htm") == 0)

        content = "text/html";

    else if ( strcmp(extname,"css") == 0 )

        content = "text/css";

    else if ( strcmp(extname,"gif") == 0 )

        content = "image/gif";

    else if ( strcmp(extname,"jpeg") == 0 || strcmp(extname,"jpg") == 0)

        content = "image/jpeg";

    else if ( strcmp(extname,"png") == 0)

        content = "image/png";

#ifdef DEBUG

    printf("HTTP/1.1 200 OK ");

    printf("Content-Type: %s ",content);

#endif

    fprintf(cfp,"HTTP/1.1 200 OK ");

    fprintf(cfp,"Content-Type: %s ",content);

    return 0;

}

 

//get the extent name of the file

char* getextname(char* filepath)

{

    char* p;

    if(( p  =  strrchr(filepath,'.')) != NULL)

               return p+1;

    return NULL;          

}

 

//invoked by pthread_create

void* start_routine(void* arg)

{

    ARG *info;

    info = (ARG *)arg;

    //handle client's requirement

    process_cli(info->connfd, info->client);

 

    delete arg;

    pthread_exit(NULL);

}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/manio/archive/2006/10/14/1334558.aspx

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值