zoukankan      html  css  js  c++  java
  • Linux_C socket 服务器(cat ,execl功能)

    客户端和web服务器交互的基本结构如下:

      (1)客户端发送请求

                GET filename HTTP/version

         可选参数

         空行

     (2)服务器发送应答

                 HTTP/version status-code status-message

                 附加信息

                 空行

                  内容

    webserv.c

    
    
      1 /* webserv.c    a minimal web server (version 0.2)
      2  * usage : webserv portnumber
      3  */
      4 #include <stdio.h>
      5 #include <sys/types.h>
      6 #include <sys/socket.h>
      7 #include <string.h>
      8 #include <sys/stat.h>
      9 #include <netinet/in.h>
     10 #include <netdb.h>
     11 
     12 /**************************************************************
     13  * 下面I/O的函数一些总结:
     14  *   1.可以在参数列表中指定并可以格式化输出函数: fprintf();
     15  *          eg:fprintf(stderr, "usage: webserv portnum");
     16  *             fprintf((FILE*)fp, "HTTP/1.0 200 OK
    ");
     17  *   2.从指定FILE指针中读取一字符串, char* fgets(char* buf, int size, FILE* stream)
     18  *          buf为保存字符的内存空间,直到出现换行、文件尾、已读了size-1个字符为止,最后加NULL作为字符串结束。返回NULL表示出错。
     19  *          eg:fgets(request, BUFSIZ, fpin);
     20  *   3.读一个字符,写一个字符。 eg: while((c=getc(fpfile))!=EOF) putc(c, fpsock);
     21  *************************************************************/
     22 
     23 
     24 int make_server_socket(int);
     25 
     26 int main(int argc, char* argv[]) {
     27   int sock, fd;
     28   FILE * fpin;
     29   char request[BUFSIZ];
     30   
     31   if(argc==1) {
     32     fprintf(stderr , "usage :webserv portnum.
    ");
     33     exit(1);
     34   }
     35   sock=make_server_socket(atoi(argv[1]));
     36   if(sock==-1)
     37     exit(2);
     38   while(1) {
     39     /* take a call and buffer it */
     40     fd=accept(sock, NULL, NULL);
     41     fpin=fdopen(fd, "r");
     42     /* read request */
     43     fgets(request, BUFSIZ, fpin);
     44     printf("get a call ; request = %s", request);
     45     read_til_crnl(fpin);
     46     /* do what client asks */
     47     process_rq(request, fd);
     48     
     49     fclose(fpin);
     50   }
     51   return 0;
     52 }
     53 
     54 int make_server_socket(int portnum) {
     55   int sock;
     56   struct sockaddr_in saddr;
     57   struct hostent *hp;
     58   char hostname[BUFSIZ];
     59   
     60   sock=socket(PF_INET, SOCK_STREAM, 0);
     61   if(sock==-1)
     62     return -1;
     63   
     64   gethostname(hostname, BUFSIZ);
     65   hp=gethostbyname(hostname);
     66   bzero(&saddr, sizeof(saddr));
     67   bcopy((void*)hp->h_addr, (void*)&saddr.sin_addr, hp->h_length);
     68   saddr.sin_port=htons(portnum);
     69   saddr.sin_family=AF_INET;
     70   
     71   if(bind(sock, (struct sockaddr*)&saddr, sizeof(saddr))!=0)
     72     return -1;
     73   if(listen(sock ,1)!=0)
     74     return -1;
     75   return sock;
     76 }
     77 
     78 /**********************************************************************
     79  * read_til_crnl(FILE* )
     80  * skip over all request info until a CRNL is seen
     81  *********************************************************************/
     82 read_til_crnl(FILE* fp) {
     83   char buf[BUFSIZ];
     84   while(fgets(buf, BUFSIZ, fp)!=NULL && strcmp(buf, "
    ")!=0)
     85     ;
     86 }
     87 
     88 /*********************************************************************
     89  * process_rq(char* rq, int fd)
     90  * do what the request asks for and write reply to fd
     91  * handles request in a new process
     92  * rq is HTTP command: GET /foo/bar.html HTTP/1.0
     93  ********************************************************************/
     94 process_rq(char *rq, int fd) {
     95   char cmd[BUFSIZ], arg[BUFSIZ];
     96   /*creat a new process and return if not the child*/
     97   if(fork()!=0) 
     98     return ;
     99   strcpy(arg, "./");   /* precede args with .*/
    100   if(sscanf(rq, "%s %s", cmd, arg+2)!=2)
    101     return ;
    102   if(strcmp(cmd, "GET")!=0)
    103     cannot_do(fd);
    104   else if(not_exist(arg))
    105     do_404(arg, fd);
    106   else if(isadir(arg))
    107     do_ls(arg, fd);
    108   else if(ends_in_cgi(arg))
    109     do_exec(arg, fd);
    110   else 
    111     do_cat(arg, fd);
    112 }
    113 
    114 
    115 
    116 /*********************************************************
    117  * the reply header thing: all functions need one
    118  * if content_type is NULL then don't send content type
    119  ********************************************************/
    120 header(FILE* fp, char * content_type) {
    121   fprintf(fp, "HTTP/1.0 200 OK
    ");
    122   if(content_type)
    123     fprintf(fp, "Content-type: %s
    ", content_type);
    124 }
    125 
    126 /********************************************************* 
    127  * simple functions first:
    128  *   cannot_do(fd): unimplemented HTTP command
    129  * and  do_404*(item ,fd)  no such object
    130  ********************************************************/
    131 
    132 cannot_do(fd) {
    133   FILE *fp=fdopen(fd, "w");
    134   
    135   fprintf(fp, "HTTP/1.0 501 Not Implemented
    ");
    136   fprintf(fp, "Content-type: text/plain
    ");
    137   fprintf(fp, "
    ");
    138   
    139   fprintf(fp, "That command is not yet implemented
    ");
    140   fclose(fp);
    141 }
    142 
    143 do_404(char* item, int fd) {
    144   FILE* fp=fdopen(fd, "w");
    145   
    146   fprintf(fp, "HTTP/1.0 404 Not Found
    ");
    147   fprintf(fp, "Content-type:text/plain
    ");
    148   fprintf(fp, "
    " );
    149   
    150   fprintf(fp, "The item you requested: %s
    is not found
    ", item);
    151   fclose(fp);
    152 }
    153 
    154 /******************************************************************
    155  * the directory listing sectoin
    156  * isadir() uses stat, not_exist() uses stat
    157  * do_ls runs ls. It should not
    158  *****************************************************************/
    159 
    160 isadir(char *f) {
    161   struct stat info;
    162   return (stat(f, &info)!=-1 && S_ISDIR(info.st_mode));
    163 }
    164 
    165 not_exist(char *f) {
    166   struct stat info;
    167   return (stat(f, &info)==-1);
    168 }
    169 
    170 do_ls(char *dir, int fd) {
    171   FILE* fp;
    172   fp=fdopen(fd, "w");
    173   header(fp, "text/plain");
    174   fprintf(fp, "
    ");
    175   fflush(fp);
    176   
    177   dup2(fd, 1);   /*注意这里的文件标识符为fd,即是socket单位,而不是fdopen()的返回值,切记切记*/
    178   dup2(fd, 2);
    179   close(fd);
    180   execlp("ls", "ls", "-l",dir, NULL);
    181   perror(dir);
    182   exit(1);
    183 }
    184 
    185 /*******************************************************
    186  * the cgi stuff function to check extension and
    187  * one to run the program.
    188  ******************************************************/
    189 char * file_type(char* f) {
    190   /* returns 'extension' of file */
    191   char *cp;
    192   if((cp=strrchr(f, '.'))!=NULL)
    193     return cp+1;
    194   return "";
    195 }
    196 
    197 ends_in_cgi(char* f) {
    198   return (strcmp(file_type(f) , "cgi")==0);
    199 }
    200 
    201 do_exec(char *prog, int fd) {
    202   FILE *fp;
    203   
    204   fp=fdopen(fd, "w");
    205   header(fp, NULL);
    206   fflush(fp);
    207   dup2(fd, 1);
    208   dup2(fd, 2);
    209   close(fd);
    210   execl(prog, prog, NULL);
    211   perror(prog);
    212 }
    213 
    214 /*******************************************************************
    215  * do_cat(filename, fd)
    216  * sends back contents after a header
    217  ******************************************************************/
    218 do_cat(char* f, int fd) {
    219   char *extension = file_type(f);
    220   char *content = "text/plain";
    221   FILE *fpsock, *fpfile;
    222   int c;
    223   
    224   if(strcmp(extension, "html")==0)
    225     content = "text/html";
    226   else if(strcmp(extension, "gif")==0)
    227     content = "image/gif";
    228   else if(strcmp(extension, "jpg")==0)
    229     content = "image/jpeg";
    230   else if(strcmp(extension, "jpeg")==0)
    231     content = "image/jpeg";
    232 
    233   fpsock = fdopen(fd, "w");
    234   fpfile = fopen(f, "r");
    235   if(fpsock != NULL && fpfile!=NULL) {
    236     header(fpsock, content);
    237     fprintf(fpsock, "
    ");
    238     while((c=getc(fpfile))!=EOF)
    239       putc(c, fpsock);
    240     fclose(fpfile);
    241     fclose(fpsock);
    242   }
    243   exit(0);
    244 }
    
    

    用法说明: gcc webserv.c -o webserv

     ./webserv 12345(端口号)

    然后在浏览器中输入主机名加端口号可访问

     注意:在do_ls()中,dup2(sock_in, 1),dup2(sock_in,2),一定要注意这一点,重定向的应该是sockid而不是fin=fdopen(sockid,"w").

  • 相关阅读:
    C# windows store socket:unknown system invalid operation exception 在意外的时间
    (转)回调函数
    VIM 安装taglist
    linux 修改时区
    SpringBoot专栏(二) -- 搭建第一个SpringBoot项目
    Jmeter接口压力测试,Java.net.BindException: Address already in use: connect
    SpringBoot专栏(一) -- SpringBoot简介
    16.查询范围
    8-数据库操作
    5.请求和响应
  • 原文地址:https://www.cnblogs.com/wizzhangquan/p/4095160.html
Copyright © 2011-2022 走看看