C Language Implementation PHP server

Source: Internet
Author: User
Tags php server
Principle Introduction

Declaration of originality:

How the HTTP protocol works

Connection: The Web browser establishes a connection to the Web server and opens a virtual file called a socket (socket), which establishes a successful connection establishment.
Request: The Web browser submits a request to the Web server through a socket. HTTP requests are typically GET or post commands (the post is used for the pass of the form parameter). The format of the Get command is:
GET path/file name http/1.0
The file name indicates which files are accessed, and http/1.0 indicates the HTTP version used by the Web browser.

Answer: After the Web browser submits the request, it is routed to the Web server via the HTTP protocol. After the Web server is received, the transaction is processed, and the results are passed back to the Web browser via HTTP to display the requested page on the Web browser.


Then return to the Web page content to the client, the client is more Conntent-type to parse


Code implementation

In fact, the Web server is a generic socket server, but it complies with the HTTP protocol to achieve it


server.c////David J. malan//malan@harvard.edu////feature test macro requirements#define _gnu_source#define _XOPEN _source 700#define _xopen_source_extended//limits on a HTTP request ' s size, based on Apache ' s//http://httpd.apache.org/ Docs/2.2/mod/core.html#define limitrequestfields 50#define limitrequestfieldsize 4094#define LimitRequestLine 8190// Number of octets for buffered reads#define octets 512//header Files#include
 
  #include #include
  
   #include
   
    #include
    
     #include
     
      #include
      
       #include
       
        #include
        
         #include
         
          #include
          
            Typestypedef Char octet;//prototypesbool connected (void); bool Error (unsigned short code); void handler (int signal); SS ize_t load (void), const char* Lookup (const char* extension), ssize_t parse (void), void reset (void), void start (short port, const char* path); void stop (void);//server ' s rootchar* root = null;//file descriptor for Socketsint cfd =-1, sfd = -1;/ /buffer for requestoctet* request = null;//file pointer for filesfile* file = null;//buffer for response-bodyoctet* bod y = null;int Main (int argc, char* argv[]) {//a global variable defined in errno.h this ' s "set by system//calls and some L Ibrary functions [to a nonzero value]//in the event of an error to indicate what went wrong ' errno = 0;//default to a ran Dom Portint port = 0;//usageconst char* usage = "usage:server [-P port]/path/to/root";//Parse command-line Argumentsin T Opt;while (opt = getopt (argc, argv, "HP:"))! =-1) {switch (opt) {//-hcase ' h ':p rintf ("%s\n", usage); return 0;//-P port Case ' P ':p ort = atoi (Optarg); break;}} Ensure Port is a non-negative short and path to server's root is specifiedif (Port < 0 | | port > Shrt_max | | argv [Optind] = = NULL | | Strlen (Argv[optind]) = = 0) {//Announce usageprintf ("%s\n", usage);//return 2 just like bash ' s Builtinsreturn 2;} Start ServerStart (port, Argv[optind]);//Listen for SIGINT (aka CONTROL-C) signal (SIGINT, handler);//Accept Connection S one at a timewhile (true) {//reset server ' s statereset ();//wait until client is CONNECTEDIF (connected ()) {//Parse Clie NT ' s HTTP requestssize_t octets = Parse (); if (octets = =-1) {continue;} Extract request ' s request-line//http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.htmlconst char* haystack = request;char* needle = strstr (haystack, "\ r \ n"), if (needle = = NULL) {error (n); continue;} else if (Needle-haystack + 2 > Limitrequestline) {error (414); continue;} Char Line[needle-haystack + 2 + 1];strncpy (line, haystack, Needle-haystack + 2); Line[needle-haystack + 2] = ' + ';// Log request-lineprintf ("\n%s ", line);//todo:validate request-linechar* method = line;char* request_target;char* version;char* absolute_path; char* s1;s1 = strstr (line, ""); if (S1 = = NULL | | (Version = STRSTR (S1 + 1, "")) = = NULL | | STRNCMP (line + sizeof)-2, "\ r \ n", 2) = = 0) {error]; continue;} Request_target = StrDup (S1 + 1); Request_target[version-s1-1] = ' + ';//printf ("Request_target is%s, version is%s", re Quest_target, version); if (strncmp (method, "GET", 3)! = 0) {error (405); continue;} if (strncmp (Request_target, "/", 1)! = 0) {error (501); continue;} if (STRCHR (request_target, ' \ "')! = NULL) {error (n); continue;} if (strncmp (version + 1, "http/1.1", 8)! = 0) {error (505); continue;} if (STRCHR (Request_target, '. ') = = NULL) {error (501); continue;} Todo:extract Query from Request-targetchar *query = STRCHR (Request_target, '? '); if (query = = NULL) query = ""; elsequery = query + 1;//printf ("Query is%s\n", query);//todo:concatenate Root and absolute -pathabsolute_path = StrDup (request_target);//printf ("%s.%D\n ", Absolute_path, Query-request_target); if (strcmp (query," ")! = 0) Absolute_path[query-request_target-1] = ' + ';//p rintf ("Absolute path is%s\n", Absolute_path); char *path = (char*) malloc (n); strcpy (path, root);//strcat (Path, "/"); strcat (path, absolute_path);//printf ("Path is%s\n", path);//todo:ensure Path Existsif (Access (path, F_OK) = =-1) {Error (404); continue;} Todo:ensure path is Readableif (Access (path, R_OK) = = 1) {error (403); continue;} Todo:extract path ' s extensionchar* extension;if ((Extension = STRRCHR (Absolute_path, '. ')) = = NULL) {error (501); Contin UE;} Extension = extension + 1;//printf ("extension is%s\n", extension);//Dynamic Contentif (strcasecmp ("php", extension) = = 0 ) {//Open pipe to PHP interpreterchar* format = "query_string=\"%s\ "redirect_status=200 script_filename=\"%s\ "php-cgi"; Char command[strlen (format) + (strlen (path)-2) + (strlen (query)-2) + 1];sprintf (command, format, query, path); file = P Open (Command, "R"); if (file = = NULL) {error (500); continue;} Load filessize_t size = load (); if (size = =-1) {error ($); continue;} Subtract php-cgi ' s headers from body's size to get content ' s lengthhaystack = Body;needle = Memmem (haystack, size, "\r\ N\r\n ", 4); if (needle = = NULL) {error ($); continue;} size_t length = size-(needle-haystack + 4);//Respond to Clientif (dprintf (CFD, http/1.1 ok\r\n) < 0) {Continu e;} if (dprintf (CFD, "connection:close\r\n") < 0) {continue;} if (dprintf (CFD, "Content-length:%i\r\n", Length) < 0) {continue;} if (write (CfD, body, size) = =-1) {continue;}} Static contentelse{//look up file ' s MIME typeconst char* type = lookup (extension), if (type = = NULL) {error (501); Continu e;} Open Filefile = fopen (path, "R"), if (file = = NULL) {error ($); continue;} Load filessize_t length = load (); if (length = =-1) {error ($); continue;} Todo:respond to client//respond with status-linedprintf (CFD, "http/1.1 ok\r\n");//respond with Connection header dprintf (CFD, "connection:close\r\n");//Respond With Content-length headerdprintf (CFD, "Content-length:%i\r\n", Length);//Respond with Content-type headerdprintf (CFD , "content-type:text/html\r\n");//Respond with crlfdprintf (CFD, "\ r \ n"); write (CfD, body, length);} Announce okprintf ("\033[32m");p rintf ("http/1.1 OK");p rintf ("\033[39m\n");}} /** * Accepts a connection from a client, blocking (i.e., waiting) until one is heard. * Upon success, returns true; Upon failure, returns false. */bool connected (void) {struct sockaddr_in cli_addr;memset (&cli_addr, 0, sizeof (CLI_ADDR)); socklen_t Cli_len = sizeof (CLI_ADDR), cfd = Accept (sfd, (struct sockaddr*) &cli_addr, &cli_len); if (cfd = =-1) {return false;} return true;} /** * Handles Client errors (4xx) and server errors (5xx). */bool error (unsigned short code) {//Ensure client's socket is openif (cfd = =-1) {return false;} Ensure code is within RangeIf (Code < | | code > 599) {return false;} Determine Status-line ' s phrase//http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1const char* phrase = Null;switch (code) {Case 400:phrase = ' bad Request '; break;case 403:phrase = "for Bidden "; Break;case 404:phrase = "Not Found"; Break;case 405:phrase = "Method not allowed"; Break;case 413:phrase = "Request Entity Too Large"; Break;case 414:phrase = "Request-uri Too Long"; Break;case 418:phrase = "I ' m a teapot"; Break;case 500:phrase = "Internal Server Error"; Break;case 501:phrase = "not implemented"; Break;case 505:phrase = "HTTP Version not supported"; break;} if (phrase = = NULL) {return false;} templatechar* template = "
           <title>%i%s</title>
           

%i%s

"; Char content[strlen (template) + 2 * ((int) log10 (code) + 1-2) + 2 * (strlen (phrase)-2) + 1];int length = sprintf (con Tent, template, code, phrase, code, phrase);//Respond with Status-lineif (dprintf (CFD, "http/1.1%i%s\r\n", code, phrase ) < 0) {return false;} Respond with Connection Headerif (dprintf (CFD, "connection:close\r\n") < 0) {return false;} Respond with Content-length Headerif (dprintf (CFD, "Content-length:%i\r\n", Length) < 0) {return false;} Respond with Content-type Headerif (dprintf (CFD, "content-type:text/html\r\n") < 0) {return false;} Respond with Crlfif (dprintf (CFD, "\ r \ n") < 0) {return false;} Respond with Message-bodyif (write (CfD, content, length) = =-1) {return false;} Announce response-lineprintf ("\033[31m");p rintf ("http/1.1%i%s", code, phrase);p rintf ("\033[39m\n"); return true;} /** * Loads file into message-body. */ssize_t load (void) {///ensure file is openif (file = = NULL) {return-1;} Ensure body isn ' t already loadedif (body! =NULL) {return-1;} Buffer for Octetsoctet buffer[octets];//read filessize_t size = 0;while (true) {//try to read a buffer ' s worth of octe tsssize_t octets = fread (buffer, sizeof (octet), octets, file);//Check for Errorif (ferror (file)! = 0) {if (BODY = NULL) {f Ree (body); body = NULL;} return-1;} If octets were read, append to Bodyif (octets > 0) {BODY = ReAlloc (body, size + octets); if (BODY = = NULL) {return-1;} memcpy (body + size, buffer, octets); size + = octets;} Check for Eofif (feof (file)! = 0) {break;}} return size;} /** * Handles signals. */void handler (int signal) {//CONTROL-CIF (signal = SIGINT) {//ensure this isn ' t considered an error//(as might otherwis E happen after a recent 404) errno = 0;//announce stopprintf ("\033[33m");p rintf ("Stopping server\n");p rintf ("\033[39m") ;//Stop Serverstop ();}} /** * Returns MIME type for supported extensions, else NULL. */const char* Lookup (const char* extension) {//Todoif (strcasecmp (extension, "CSS")) return "Text/css"; if (strcasecmp ( ExtensiOn, "HTML")) return "text/html", if (strcasecmp (extension, "GIF")) return "Image/gif"; if (strcasecmp (extension, "ico")) Return "Image/x-icon", if (strcasecmp (extension, "JPG")) return "Image/jpeg", if (strcasecmp (extension, "JS")) return " Text/javascript "; if (strcasecmp (extension," PNG ") return" Image/png "; return NULL;} /** * Parses an HTTP request. */ssize_t Parse (void) {//Ensure client ' s socket is openif (cfd = =-1) {return-1;} Ensure request isn ' t already parsedif (Request! = NULL) {return-1;} Buffer for Octetsoctet buffer[octets];//parse requestssize_t length = 0;while (True) {//read from socketssize_t OCTETS = Read (cfd, buffer, sizeof (octet) * OCTETS); if (OCTETS = =-1) {error ($); return-1;} If octets has been read, remember new Lengthif (octets > 0) {request = ReAlloc (request, length + octets); if (Request = = NULL) {return-1;} memcpy (Request + length, buffer, octets); length + = octets;} else if nothing ' s been read, socket ' s been closedelse{return-1;} Search for CRLF Crlfint ofFset = (Length-octets < 3)? length-octets:3;char* haystack = Request + length-octets-offset;char* needle = Memmem (haystack, request + length- Haystack, "\r\n\r\n", 4); if (needle! = NULL) {//trim to one CRLF and null-terminatelength = needle-request + 2 + 1;requ EST = realloc (request, length); if (request = = NULL) {return-1;} Request[length-1] = ' n '; If buffer ' s full and we still haven ' t found CRLF crlf,//then request is too Largeif (length-1 >= limitrequestline + Limitrequestfields * limitrequestfieldsize) {error (413); return-1;}} return length;} /** * Resets server ' s state, deallocating any resources. */void Reset (void) {//free response ' s bodyif (body! = NULL) {free (body); body = null;} Close Fileif (file! = null) {fclose (file); file = null;} Free Requestif (Request! = null) {free (request); request = NULL;} Close client ' s socketif (cfd! =-1) {close (cfd); cfd =-1;}} /** * Starts server. */void Start (short port, const char* path) {//path to server ' s Rootroot= Realpath (path, NULL), if (root = = null) {stop ();} Ensure root existsif (access (root, F_OK) = = 1) {stop ();} Ensure root is Executableif (access (root, X_OK) = = 1) {stop ();} Announce rootprintf ("\033[33m");p rintf ("Using%s for server ' s root, size is%ld", root, sizeof (root));p rintf ("\033[39m \ n ");//Create a SOCKETSFD = Socket (af_inet, sock_stream, 0); if (sfd = =-1) {Stop ();} Allow reuse of address (to avoid "address already in use") int optval = 1;setsockopt (SFD, Sol_socket, SO_REUSEADDR, &amp ; optval, sizeof (optval));//Assign name to Socketstruct sockaddr_in serv_addr;memset (&serv_addr, 0, sizeof (serv_ addr)); serv_addr.sin_family = Af_inet;serv_addr.sin_port = htons (port); serv_addr.sin_addr.s_addr = htonl (Inaddr_any) ; if (Bind (SFD, (struct sockaddr*) &serv_addr, sizeof (serv_addr)) = =-1) {Stop ();} Listen for Connectionsif (Listen (SFD, somaxconn) = =-1) {Stop ();} Announce port in usestruct sockaddr_in addr;socklen_t addrlen = sizeof (addr); if (GetSockName (SFD), (struct SOCKADDr*) &addr, &addrlen) = =-1) {Stop ();} printf ("\033[33m");p rintf ("Listening on Port%i", Ntohs (Addr.sin_port));p rintf ("\033[39m\n");} /** * Stop Server, deallocating any resources. */void Stop (void) {//preserve errno across this function ' s library callsint ERRSV = errno;//Reset server ' s statereset (); /free root, which is allocated by realpathif (root = NULL) {free (root);} Close Server Socketif (SFD! =-1) {close (SFD);} Terminate Processif (ERRSV = = 0) {//Successexit (0);} else{//announce errorprintf ("\033[33m");p rintf ("%s", Strerror (ERRSV));p rintf ("\033[39m\n");//Failureexit (1);}}


Compilation method
Gcc-o Server Server.c-lm

How to Run

./server-p 8080 Public

Where the public directory is stored in HTML and PHP files

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.