C++实现一个web服务器, 弱智版服务器

监听本地的8888端口, 当在浏览器中访问这个地址的时候, 返回一堆HTML数据, 这种方式返回的数据不稳定,不同浏览器解析不同, 因为我们没有定义返回文件类型:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_port = htons(8888);
    address.sin_addr.s_addr = inet_addr("192.168.0.58");
    int ret = bind(sock , (const struct sockaddr*)&address , sizeof(address));
    ret = listen(sock, 100);
    printf("lisening..\n");

    struct sockaddr_in client_address;
    socklen_t len;
    int newsock = accept(sock, (struct sockaddr*)&client_address, &len);
    printf("client conneting\n");
    FILE *fp = fopen("./html/index.html","rb");
    char buf[1024] = {0};
    fread(buf, 1024, 1, fp);
    printf("content is %s\n", buf);
    send(newsock, buf, strlen(buf), 0);
    close(newsock);
    close(sock);    
    return 0;
}

给服务器的返回设置文件类型和文件大小信息, 避免页面出现乱码和页面的正常解析:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_port = htons(8888);
    address.sin_addr.s_addr = inet_addr("192.168.1.102");
    int ret = bind(sock , (const struct sockaddr*)&address , sizeof(address));
    ret = listen(sock, 100);
    printf("lisening..\n");

    struct sockaddr_in client_address;
    socklen_t len;
    int newsock = accept(sock, (struct sockaddr*)&client_address, &len);
    printf("client conneting\n");

    //char recvData[1024] ={0};
    //recv(newsock, recvData, sizeof(recvData), 0);
    //printf("receive data:%s", recvData);
    FILE *fp = fopen("./html/index.html","rb");

        if( fp == NULL ){
            printf("failed to open img\n");
       }
    fseek(fp, 0, SEEK_END);
        long fileLen = ftell(fp);
        fseek(fp, 0, SEEK_SET);

        char buf[1024] = {0};
        strcat(buf, "HTTP/1.0 200 OK\r\n");
        strcat(buf, "Content-Type: text/html;charset=UTF-8\r\n");

        char contentLength[256] = {0};
        sprintf(contentLength, "Content-Length: %ld\r\n\r\n", fileLen);
        strcat(buf, contentLength);

        fread(buf+strlen(buf), 1024, 1, fp);
    send(newsock, buf, strlen(buf), 0);
    close(newsock);
    close(sock);    
    return 0;
}

打开本地的PNG图片,并返回给客户端浏览器, 和上面的代码还有一点区别就是, 服务器有返回Content-type和Content-Length :

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_port = htons(8888);
    address.sin_addr.s_addr = inet_addr("192.168.1.102");
    int ret = bind(sock , (const struct sockaddr*)&address , sizeof(address));
    ret = listen(sock, 100);
    printf("lisening..\n");

    struct sockaddr_in client_address;
    socklen_t len;
    int newsock = accept(sock, (struct sockaddr*)&client_address, &len);
    printf("client conneting\n");
    FILE *fp = fopen("./imgs/img.png","rb");
    if( fp == NULL ){
        printf("failed to open img\n");
    }
    fseek(fp, 0, SEEK_END);
    long fileLen = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    char buf[40960] = {0};
    strcat(buf, "HTTP/1.0 200 OK\r\n");
    strcat(buf, "Content-Type: image\png;charset=UTF-8\r\n");

    char contentLength[256] = {0};
    sprintf(contentLength, "Content-Length: %ld\r\n\r\n", fileLen);
    strcat(buf, contentLength);

    //strlen just string length; but sizeof return all the size;
    fread(buf+strlen(buf), 40960, 1, fp);
    send(newsock, buf, 40960, 0);

    close(newsock);
    close(sock);    
    return 0;
}

搭建一个服务器:

/*****************************************************************
  system:kali

  enviroment:g++

  compile command:gcc webServer.c -g -o webServer -lpthread

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

#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*);

void* getHead(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 \n",cmd);

#endif

        //is this a file or dir or notexist?
    printf("filepath is .... : %s\n", filepath);
        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\n",filepath);

#endif

                    sendobj(connectfd, filepath);

            }

        }else{

#ifdef DEBUG

            printf("404 ");

#endif

            msg404(connectfd);

        }

    }else{

#ifdef DEBUG

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

#endif

    }

#ifdef DEBUG

    printf(":::::::::::::end::::::::::::::: \n");    

#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* fp,*cfp;
    char buf[40960] = {0};


    int c;

    fp = fopen(serverfilepath,"rb");

    printf("filepath is %s \n ", serverfilepath);

    if( fp == NULL ){
    printf("failed to open html file\n");
    }
    fseek(fp, 0, SEEK_END);
    long fileLen = ftell(fp);
    fseek(fp, 0, SEEK_SET);


    strcat(buf, "HTTP/1.0 200 OK\r\n");
    strcat(buf, "Content-Type:  ");
    char* fileExt = getextname(serverfilepath);
    strcat(buf, (char *)getHead(fileExt));
    strcat(buf, ";charset=UTF-8\r\n");

    char contentLength[256] = {0};
    sprintf(contentLength, "Content-Length: %ld\r\n\r\n", fileLen);
    strcat(buf, contentLength);

    fread(buf+strlen(buf), 40960, 1, fp);
    printf("buf is %s\n", buf);
    send(connectfd, buf, strlen(buf), 0);

    return 0;

}

//write the packet header to the client

void* getHead(char* extname)

{

#ifdef DEBUG

    printf("INGETHEAD:::::::extname is %s::::::: \n",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";

    return (void *)content;


}



//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;

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

    delete arg;

    pthread_exit(NULL);

}

C语言的限制很少..类型可以随便转..系统相对于把所有的权利交给我们了, 所以C语言容易出问题

C++搭建一个web服务器:http://www.cppblog.com/cuijixin/archive/2008/07/02/55112.html
原文链接: https://www.cnblogs.com/diligenceday/p/7087696.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/256012

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 上午9:41
下一篇 2023年2月14日 上午9:43

相关推荐