Simple Linux Web Server (C Language)

Simple Linux Web Server (C Language)

I. Project Introduction

The web server provides static page (HTML) resources, the transport layer is based on the TCP protocol, and the application layer is based on the HTTP protocol.
The browser sends an HTTP request, and the server parses the request after receiving it; parses out the resource path requested by the browser, verifies whether the resource is legal and confirms its type, obtains the resource content locally, organizes it into an HTTP response and sends it back to the web server. The web server supports concurrent processing (multi-threading).

Makefile can provide quick compilation and generation of executable files.

# Quickly compile and generate .o files and executable files
$ make
# Quickly remove all of the .o files and executable files
$ make clean

II. Project Structure

  1. Diagram

在这里插入图片描述

  1. Module Introduction
    a. HTTP Module ( http.h, http.c)
    • Functionality

      Parse HTTP requests:

      After the HTTP request sent from the client is received by the server, important data to be used later must be extracted from the request and stored.

      Construct HTTP respond:

      After receiving the client’s HTTP request, the server sends a response back to the client. The response is divided into two parts: the response header and the response body. The response header is completed by this module.

      • Function and Variable:
    // HTTP request
    typedef struct tag_HttpRequest {...} HTTP_REQUEST;
    // HTTP respond
    typedef struct tag_HttpRespond {...} HTTP_RESPOND;
    // Parse request
    int parseRequest(char const* req, HTTP_REQUEST* hreq);
    // Construct repond head
    void constructHead(HTTP_RESPOND const* hres, char* head);
    
    b. Resource Module (resource.h, resource.c, mime.h)
    • Functionality:

      Determine whether the file exists and the file type. If the file can not be found in server, then server send the 404 respond to client.

    • Function and Variable:

      // Filename Suffix: Content-Type Mapping Table
      static struct{...} s_minme[] = {...};
      // Search resource
      int searchResource(char const* path);
      // Identify file types
      int identifyType(char const* path, char* type);
      
    c. Socket Module (socket.h, socket.c)
    • Functionality

      Initializing the socket: The server transport layer uses the TCP protocol. When setting up the server, it needs to create sockets, organize address structures, bind, listen and other functions.

      Waiting for and receiving the client’s connection request: When the client needs to access the server, it needs to complete a three-way handshake. The server needs to wait for the arrival of the connection request, complete the three-way handshake, and establish a communication connection with the client.

      Receive the client’s HTTP request: After the server and the client establish a communication connection, the client sends an HTTP request to the server. The server needs to receive the request and complete the storage for subsequent operations.

      Send response header: The response header is constructed by the HTTP module. In this module, it is responsible for sending the constructed response header to the client.

      Sending the response body: The response body is the specific file content requested by the client. The server needs to obtain the file locally, read the content of the file, and send it to the client.

      Close the socket.

    • Function and Variable:

    // Initialze socket
    int initSocket(short port);
    // Accept client connection
    int acceptClient(void);
    // Receive request
    char* recvRequest(int conn);
    // Send respond head
    int sendHead(int conn, char const* head);
    // Send respond Body
    int sendBody(int conn, char const* path);
    // Terminate socket
    void terminateSocket(void);
    
    d. Thread Module (client.h, client.c)
    • Functionality

      This module is actually a process function of threads, and each thread is responsible for communicating with a client.

      Receive requests from clients, parse the content of the requests, and obtain key information such as resource paths. Determine the resource requested by the client to see if it exists locally. If it does not exist, respond to the client with a 404.html file and determine the file type requested by the client. Construct the response header and complete the return of the response header and response body.

    • Function and variable:

      // Client parameter
      typedef struct tag_ClientArgs{...} CA;
      // Client thread process
      void* client(void* arg);
      
    e. Signals Module (signals.h, signals.c)
    • Functionality

      In this module, most signals should be ignored (not blocked) to improve the server’s working ability and efficiency. Signals that are not ignored: SIGINT(2) and SIGTERM(15) are used for control, SIGKILL(9) and SIGSTOP(19) cannot be ignored, and signals 32 and 33 do not exist.

    • Function and varaiable:

      // Initialze signals
      int initSignals(void);
      
    f. Server Module (server.h, server.c)
    • Functionality

      This module is mainly responsible for receiving connection requests from clients and creating threads.

      Initialize the server: mainly responsible for completing the initialization of the server, including creating sockets, ignoring most signals, etc.

      Running server: It is mainly responsible for cyclically receiving connection requests from clients and establishing communication connections, obtaining communication sockets, creating threads, passing communication sockets into threads, and completing communication with clients.

      Terminate the server.

    • Function and variable:

      // Initialize the maximum number of file descriptors
      static int initMaxFiles(void);
      // Initialize the server
      int initServer(short port);
      // Run server
      int runServer(char const* home);
      // Terminate server
      void terminateServer(void);
      
    g. Main Module (main.c)
    • Functionality

      This module is the last module implemented in the project, that is, the main function. In the main function, the functions of the server module are called to complete the initialization and running functions of the server. In this module, you can specify the port and resource path bound to the server based on the content passed by the command line parameters. If the command line arguments are missing, the default port number and home directory will be used.

    • Function and variable:

      // main
      int main(int argc, char* argc[]);
      
    III. Test

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

IV. Project Code
  1. HTTP Module

    1. http.h

      #ifndef _HTTP_H
      #define _HTTP_H
      
      #include <limits.h>
      #include <sys/types.h>
      
      // HTTP request
      typedef struct tag_HttpRequest{
              char method[32];        // Method: GET, POST...
              char path[PATH_MAX+1];  // Path of the file or directory
              char protocol[32];      // Protocol: HTTP, HTTPS...
              char connection[32];    // Connection mode: keep-alive, close
      } HTTP_REQUEST;
      
      // HTTP respond
      typedef struct tag_HttpRespond{
              char protocol[32];      // Protocol: HTTP, HTTPS...
              int status;             // Status: 404, 200...
              char description[256];       // Describe the status: 404 ---> Not Found
              char type[32];          // Resource type
              off_t length;           // off_t: signed long
              char connection[32];    // Connection mode
      } HTTP_RESPOND;
      
      // Parse request
      int parseRequest(char const* req, HTTP_REQUEST* hreq);
      
      // Construct repond head
      void constructHead(HTTP_RESPOND const* hres, char* head);
      
      #endif
      
      
    2. http.c

      #include <stdio.h>
      #define __USE_GNU
      #include <string.h>
      #include <time.h>
      #include <unistd.h>
      #include <sys/syscall.h>
      #include "http.h"
      
      // Parse request
      int parseRequest(char const* req, HTTP_REQUEST* hreq){
      	/* 
      	request looks like below
      		GET /xxx/xxx HTTP/1.1\r\n
      		Host: localhost:8000\r\n
      		User-Agent: Mozilla/5.0\r\n
      		Accept: text/html\r\n
      		Connection: keep-alive\r\n
      		\r\n
      		...
      	 */
      
      	sscanf(req, "%s%s%s", hreq->method, hreq->path, hreq->protocol);        // "GET /xxx/xxx HTTP\r\n" ---> method = GET, path = /xxx/xxx, protocol = HTTP
      	
      	char* connection = strcasestr(req, "connection");                       // Find the 'connection' in the request and does not care the case
      	if (connection != NULL){
      		sscanf(connection, "%*s%s", hreq->connection);                  // Connection: keep-alive ---> do not care the 'Connection:', hreq->connection = keep-alive
      	}
      	printf("Process:%d. Thread:%ld>>>>>> [%s][%s][%s][%s]\n", getpid(), syscall(SYS_gettid), hreq->method, hreq->path, hreq->protocol, hreq->connection); // syscall to get the realthread id
      	
      	if (strcasecmp(hreq->method, "GET")){                                   // This server only support the GET method
      		printf("Process:%d. Thread:%ld>>>>>> Invaild method.\n", getpid(), syscall(SYS_gettid));
      		return -1;
      	}
      
      	if (strcasecmp(hreq->protocol, "HTTP/1.0") && strcasecmp(hreq->protocol, "HTTP/1.1")){ // This server suport HTTP/1.0 && HTTP/1.1
      		printf("Process:%d. Thread:%ld>>>>>> Invaild protocol.\n", getpid(), syscall(SYS_gettid));
      		return -1;
      	}
      
      	return 0;
      }
      
      // Construct respond head
      void constructHead(HTTP_RESPOND const* hres, char* head){
      	/*
      	   HTTP/1.1 200 OK\r\n
      	   Sever: Webserver 1.0\r\n
      	   Date: Mon, 4 Sep 2023 00:00:00 GMT\r\n
      	   Content-Type: text/html\r\n
      	   Connection: keep-alive\r\n
      	   \r\n
      	   ...
      	 */
      
      	char dateTime[32];
      	time_t now = time(NULL);
      	strftime(dateTime, sizeof(dateTime), "%a, %d %b %Y %T GMT", gmtime(&now)); // Format time	%a ----> Mon
      
      	sprintf(head, "%s %d %s\r\n"
      			"Server: Eason Webserver 1.0\r\n"
      			"Date: %s\r\n"
      			"Content-Type: %s\r\n"
      			"Content-Length: %ld\r\n"
      			"Connection: %s\r\n\r\n", hres->protocol, hres->status, hres->description, dateTime, hres->type, hres->length, hres->connection);
      }
      
  2. Resource Module

    1. mime.h

      #ifndef _MIME_H
      #define _MIME_H
      
      static struct {
      	char suffix[256];
      	char type[256];
      }	s_mime[] = {
      	{"."       , "application/x-"                         },
      	{".*"      , "application/octet-stream"               },
      	{".001"    , "application/x-001"                      },
      	{".301"    , "application/x-301"                      },
      	{".323"    , "text/h323"                              },
      	{".906"    , "application/x-906"                      },
      	{".907"    , "drawing/907"                            },
      	{".acp"    , "audio/x-mei-aac"                        },
      	{".ai"     , "application/postscript"                 },
      	{".aif"    , "audio/aiff"                             },
      	{".aifc"   , "audio/aiff"                             },
      	{".aiff"   , "audio/aiff"                             },
      	{".a11"    , "application/x-a11"                      },
      	{".anv"    , "application/x-anv"                      },
      	{".apk"    , "application/vnd.android.package-archive"},
      	{".asa"    , "text/asa"                               },
      	{".asf"    , "video/x-ms-asf"                         },
      	{".asp"    , "text/asp"                               },
      	{".asx"    , "video/x-ms-asf"                         },
      	{".au"     , "audio/basic"                            },
      	{".avi"    , "video/avi"                              },
      	{".awf"    , "application/vnd.adobe.workflow"         },
      	{".biz"    , "text/xml"                               },
      	{".bmp"    , "application/x-bmp"                      },
      	{".bot"    , "application/x-bot"                      },
      	{".c4t"    , "application/x-c4t"                      },
      	{".c90"    , "application/x-c90"                      },
      	{".cal"    , "application/x-cals"                     },
      	{".cat"    , "application/vnd.ms-pki.seccat"          },
      	{".cdf"    , "application/x-netcdf"                   },
      	{".cdr"    , "application/x-cdr"                      },
      	{".cel"    , "application/x-cel"                      },
      	{".cer"    , "application/x-x509-ca-cert"             },
      	{".cg4"    , "application/x-g4"                       },
      	{".cgm"    , "application/x-cgm"                      },
      	{".cit"    , "application/x-cit"                      },
      	{".class"  , "java/*"                                 },
      	{".cml"    , "text/xml"                               },
      	{".cmp"    , "application/x-cmp"                      },
      	{".cmx"    , "application/x-cmx"                      },
      	{".cot"    , "application/x-cot"                      },
      	{".crl"    , "application/pkix-crl"                   },
      	{".crt"    , "application/x-x509-ca-cert"             },
      	{".csi"    , "application/x-csi"                      },
      	{".css"    , "text/css"                               },
      	{".cut"    , "application/x-cut"                      },
      	{".dbf"    , "application/x-dbf"                      },
      	{".dbm"    , "application/x-dbm"                      },
      	{".dbx"    , "application/x-dbx"                      },
      	{".dcd"    , "text/xml"                               },
      	{".dcx"    , "application/x-dcx"                      },
      	{".der"    , "application/x-x509-ca-cert"             },
      	{".dgn"    , "application/x-dgn"                      },
      	{".dib"    , "application/x-dib"                      },
      	{".dll"    , "application/x-msdownload"               },
      	{".doc"    , "application/msword"                     },
      	{".dot"    , "application/msword"                     },
      	{".drw"    , "application/x-drw"                      },
      	{".dtd"    , "text/xml"                               },
      	{".dwf"    , "application/x-dwf"                      },
      	{".dwg"    , "application/x-dwg"                      },
      	{".dxb"    , "application/x-dxb"                      },
      	{".dxf"    , "application/x-dxf"                      },
      	{".edn"    , "application/vnd.adobe.edn"              },
      	{".emf"    , "application/x-emf"                      },
      	{".eml"    , "message/rfc822"                         },
      	{".ent"    , "text/xml"                               },
      	{".epi"    , "application/x-epi"                      },
      	{".eps"    , "application/x-ps"                       },
      	{".eps"    , "application/postscript"                 },
      	{".etd"    , "application/x-ebx"                      },
      	{".exe"    , "application/x-msdownload"               },
      	{".fax"    , "image/fax"                              },
      	{".fdf"    , "application/vnd.fdf"                    },
      	{".fif"    , "application/fractals"                   },
      	{".fo"     , "text/xml"                               },
      	{".frm"    , "application/x-frm"                      },
      	{".g4"     , "application/x-g4"                       },
      	{".gbr"    , "application/x-gbr"                      },
      	{".gif"    , "image/gif"                              },
      	{".gl2"    , "application/x-gl2"                      },
      	{".gp4"    , "application/x-gp4"                      },
      	{".hgl"    , "application/x-hgl"                      },
      	{".hmr"    , "application/x-hmr"                      },
      	{".hpg"    , "application/x-hpgl"                     },
      	{".hpl"    , "application/x-hpl"                      },
      	{".hqx"    , "application/mac-binhex40"               },
      	{".hrf"    , "application/x-hrf"                      },
      	{".hta"    , "application/hta"                        },
      	{".htc"    , "text/x-component"                       },
      	{".htm"    , "text/html"                              },
      	{".html"   , "text/html"                              },
      	{".htt"    , "text/webviewhtml"                       },
      	{".htx"    , "text/html"                              },
      	{".icb"    , "application/x-icb"                      },
      	{".ico"    , "image/x-icon"                           },
      	{".iff"    , "application/x-iff"                      },
      	{".ig4"    , "application/x-g4"                       },
      	{".igs"    , "application/x-igs"                      },
      	{".iii"    , "application/x-iphone"                   },
      	{".img"    , "application/x-img"                      },
      	{".ins"    , "application/x-internet-signup"          },
      	{".ipa"    , "application/vnd.iphone"                 },
      	{".isp"    , "application/x-internet-signup"          },
      	{".IVF"    , "video/x-ivf"                            },
      	{".java"   , "java/*"                                 },
      	{".jfif"   , "image/jpeg"                             },
      	{".jpe"    , "image/jpeg"                             },
      	{".jpeg"   , "image/jpeg"                             },
      	{".jpg"    , "image/jpeg"                             },
      	{".js"     , "application/x-javascript"               },
      	{".jsp"    , "text/html"                              },
      	{".la1"    , "audio/x-liquid-file"                    },
      	{".lar"    , "application/x-laplayer-reg"             },
      	{".latex"  , "application/x-latex"                    },
      	{".lavs"   , "audio/x-liquid-secure"                  },
      	{".lbm"    , "application/x-lbm"                      },
      	{".lmsff"  , "audio/x-la-lms"                         },
      	{".ls"     , "application/x-javascript"               },
      	{".ltr"    , "application/x-ltr"                      },
      	{".m1v"    , "video/x-mpeg"                           },
      	{".m2v"    , "video/x-mpeg"                           },
      	{".m3u"    , "audio/mpegurl"                          },
      	{".m4e"    , "video/mpeg4"                            },
      	{".mac"    , "application/x-mac"                      },
      	{".man"    , "application/x-troff-man"                },
      	{".math"   , "text/xml"                               },
      	{".mdb"    , "application/msaccess"                   },
      	{".mfp"    , "application/x-shockwave-flash"          },
      	{".mht"    , "message/rfc822"                         },
      	{".mhtml"  , "message/rfc822"                         },
      	{".mi"     , "application/x-mi"                       },
      	{".mid"    , "audio/mid"                              },
      	{".midi"   , "audio/mid"                              },
      	{".mil"    , "application/x-mil"                      },
      	{".mml"    , "text/xml"                               },
      	{".mnd"    , "audio/x-musicnet-download"              },
      	{".mns"    , "audio/x-musicnet-stream"                },
      	{".mocha"  , "application/x-javascript"               },
      	{".movie"  , "video/x-sgi-movie"                      },
      	{".mp1"    , "audio/mp1"                              },
      	{".mp2"    , "audio/mp2"                              },
      	{".mp2v"   , "video/mpeg"                             },
      	{".mp3"    , "audio/mp3"                              },
      	{".mp4"    , "video/mpeg4"                            },
      	{".mpa"    , "video/x-mpg"                            },
      	{".mpd"    , "application/vnd.ms-project"             },
      	{".mpe"    , "video/x-mpeg"                           },
      	{".mpeg"   , "video/mpg"                              },
      	{".mpg"    , "video/mpg"                              },
      	{".mpga"   , "audio/rn-mpeg"                          },
      	{".mpp"    , "application/vnd.ms-project"             },
      	{".mps"    , "video/x-mpeg"                           },
      	{".mpt"    , "application/vnd.ms-project"             },
      	{".mpv"    , "video/mpg"                              },
      	{".mpv2"   , "video/mpeg"                             },
      	{".mpw"    , "application/vnd.ms-project"             },
      	{".mpx"    , "application/vnd.ms-project"             },
      	{".mtx"    , "text/xml"                               },
      	{".mxp"    , "application/x-mmxp"                     },
      	{".net"    , "image/pnetvue"                          },
      	{".nrf"    , "application/x-nrf"                      },
      	{".nws"    , "message/rfc822"                         },
      	{".odc"    , "text/x-ms-odc"                          },
      	{".out"    , "application/x-out"                      },
      	{".p10"    , "application/pkcs10"                     },
      	{".p12"    , "application/x-pkcs12"                   },
      	{".p7b"    , "application/x-pkcs7-certificates"       },
      	{".p7c"    , "application/pkcs7-mime"                 },
      	{".p7m"    , "application/pkcs7-mime"                 },
      	{".p7r"    , "application/x-pkcs7-certreqresp"        },
      	{".p7s"    , "application/pkcs7-signature"            },
      	{".pc5"    , "application/x-pc5"                      },
      	{".pci"    , "application/x-pci"                      },
      	{".pcl"    , "application/x-pcl"                      },
      	{".pcx"    , "application/x-pcx"                      },
      	{".pdf"    , "application/pdf"                        },
      	{".pdx"    , "application/vnd.adobe.pdx"              },
      	{".pfx"    , "application/x-pkcs12"                   },
      	{".pgl"    , "application/x-pgl"                      },
      	{".pic"    , "application/x-pic"                      },
      	{".pko"    , "application/vnd.ms-pki.pko"             },
      	{".pl"     , "application/x-perl"                     },
      	{".plg"    , "text/html"                              },
      	{".pls"    , "audio/scpls"                            },
      	{".plt"    , "application/x-plt"                      },
      	{".png"    , "image/png"                              },
      	{".pot"    , "application/vnd.ms-powerpoint"          },
      	{".ppa"    , "application/vnd.ms-powerpoint"          },
      	{".ppm"    , "application/x-ppm"                      },
      	{".pps"    , "application/vnd.ms-powerpoint"          },
      	{".ppt"    , "application/vnd.ms-powerpoint"          },
      	{".ppt"    , "application/x-ppt"                      },
      	{".pr"     , "application/x-pr"                       },
      	{".prf"    , "application/pics-rules"                 },
      	{".prn"    , "application/x-prn"                      },
      	{".prt"    , "application/x-prt"                      },
      	{".ps"     , "application/x-ps"                       },
      	{".ps"     , "application/postscript"                 },
      	{".ptn"    , "application/x-ptn"                      },
      	{".pwz"    , "application/vnd.ms-powerpoint"          },
      	{".r3t"    , "text/vnd.rn-realtext3d"                 },
      	{".ra"     , "audio/vnd.rn-realaudio"                 },
      	{".ram"    , "audio/x-pn-realaudio"                   },
      	{".ras"    , "application/x-ras"                      },
      	{".rat"    , "application/rat-file"                   },
      	{".rdf"    , "text/xml"                               },
      	{".rec"    , "application/vnd.rn-recording"           },
      	{".red"    , "application/x-red"                      },
      	{".rgb"    , "application/x-rgb"                      },
      	{".rjs"    , "application/vnd.rn-realsystem-rjs"      },
      	{".rjt"    , "application/vnd.rn-realsystem-rjt"      },
      	{".rlc"    , "application/x-rlc"                      },
      	{".rle"    , "application/x-rle"                      },
      	{".rm"     , "application/vnd.rn-realmedia"           },
      	{".rmf"    , "application/vnd.adobe.rmf"              },
      	{".rmi"    , "audio/mid"                              },
      	{".rmj"    , "application/vnd.rn-realsystem-rmj"      },
      	{".rmm"    , "audio/x-pn-realaudio"                   },
      	{".rmp"    , "application/vnd.rn-rn_music_package"    },
      	{".rms"    , "application/vnd.rn-realmedia-secure"    },
      	{".rmvb"   , "application/vnd.rn-realmedia-vbr"       },
      	{".rmx"    , "application/vnd.rn-realsystem-rmx"      },
      	{".rnx"    , "application/vnd.rn-realplayer"          },
      	{".rp"     , "image/vnd.rn-realpix"                   },
      	{".rpm"    , "audio/x-pn-realaudio-plugin"            },
      	{".rsml"   , "application/vnd.rn-rsml"                },
      	{".rt"     , "text/vnd.rn-realtext"                   },
      	{".rtf"    , "application/msword"                     },
      	{".rtf"    , "application/x-rtf"                      },
      	{".rv"     , "video/vnd.rn-realvideo"                 },
      	{".sam"    , "application/x-sam"                      },
      	{".sat"    , "application/x-sat"                      },
      	{".sdp"    , "application/sdp"                        },
      	{".sdw"    , "application/x-sdw"                      },
      	{".sis"    , "application/vnd.symbian.install"        },
      	{".sisx"   , "application/vnd.symbian.install"        },
      	{".sit"    , "application/x-stuffit"                  },
      	{".slb"    , "application/x-slb"                      },
      	{".sld"    , "application/x-sld"                      },
      	{".slk"    , "drawing/x-slk"                          },
      	{".smi"    , "application/smil"                       },
      	{".smil"   , "application/smil"                       },
      	{".smk"    , "application/x-smk"                      },
      	{".snd"    , "audio/basic"                            },
      	{".sol"    , "text/plain"                             },
      	{".sor"    , "text/plain"                             },
      	{".spc"    , "application/x-pkcs7-certificates"       },
      	{".spl"    , "application/futuresplash"               },
      	{".spp"    , "text/xml"                               },
      	{".ssm"    , "application/streamingmedia"             },
      	{".sst"    , "application/vnd.ms-pki.certstore"       },
      	{".stl"    , "application/vnd.ms-pki.stl"             },
      	{".stm"    , "text/html"                              },
      	{".sty"    , "application/x-sty"                      },
      	{".svg"    , "text/xml"                               },
      	{".swf"    , "application/x-shockwave-flash"          },
      	{".tdf"    , "application/x-tdf"                      },
      	{".tg4"    , "application/x-tg4"                      },
      	{".tga"    , "application/x-tga"                      },
      	{".tif"    , "image/tiff"                             },
      	{".tiff"   , "image/tiff"                             },
      	{".tld"    , "text/xml"                               },
      	{".top"    , "drawing/x-top"                          },
      	{".torrent", "application/x-bittorrent"               },
      	{".tsd"    , "text/xml"                               },
      	{".ttf"    , "application/font-woff"                  },
      	{".txt"    , "text/plain"                             },
      	{".uin"    , "application/x-icq"                      },
      	{".uls"    , "text/iuls"                              },
      	{".vcf"    , "text/x-vcard"                           },
      	{".vda"    , "application/x-vda"                      },
      	{".vdx"    , "application/vnd.visio"                  },
      	{".vml"    , "text/xml"                               },
      	{".vpg"    , "application/x-vpeg005"                  },
      	{".vsd"    , "application/vnd.visio"                  },
      	{".vsd"    , "application/x-vsd"                      },
      	{".vss"    , "application/vnd.visio"                  },
      	{".vst"    , "application/vnd.visio"                  },
      	{".vst"    , "application/x-vst"                      },
      	{".vsw"    , "application/vnd.visio"                  },
      	{".vsx"    , "application/vnd.visio"                  },
      	{".vtx"    , "application/vnd.visio"                  },
      	{".vxml"   , "text/xml"                               },
      	{".wav"    , "audio/wav"                              },
      	{".wax"    , "audio/x-ms-wax"                         },
      	{".wb1"    , "application/x-wb1"                      },
      	{".wb2"    , "application/x-wb2"                      },
      	{".wb3"    , "application/x-wb3"                      },
      	{".wbmp"   , "image/vnd.wap.wbmp"                     },
      	{".wiz"    , "application/msword"                     },
      	{".wk3"    , "application/x-wk3"                      },
      	{".wk4"    , "application/x-wk4"                      },
      	{".wkq"    , "application/x-wkq"                      },
      	{".wks"    , "application/x-wks"                      },
      	{".wm"     , "video/x-ms-wm"                          },
      	{".wma"    , "audio/x-ms-wma"                         },
      	{".wmd"    , "application/x-ms-wmd"                   },
      	{".wmf"    , "application/x-wmf"                      },
      	{".wml"    , "text/vnd.wap.wml"                       },
      	{".wmv"    , "video/x-ms-wmv"                         },
      	{".wmx"    , "video/x-ms-wmx"                         },
      	{".wmz"    , "application/x-ms-wmz"                   },
      	{".wp6"    , "application/x-wp6"                      },
      	{".wpd"    , "application/x-wpd"                      },
      	{".wpg"    , "application/x-wpg"                      },
      	{".wpl"    , "application/vnd.ms-wpl"                 },
      	{".wq1"    , "application/x-wq1"                      },
      	{".wri"    , "application/x-wri"                      },
      	{".wrk"    , "application/x-wrk"                      },
      	{".wr1"    , "application/x-wr1"                      },
      	{".ws"     , "application/x-ws"                       },
      	{".ws2"    , "application/x-ws"                       },
      	{".wsc"    , "text/scriptlet"                         },
      	{".wsdl"   , "text/xml"                               },
      	{".wvx"    , "video/x-ms-wvx"                         },
      	{".xap"    , "application/x-silverlight-app"          },
      	{".xdp"    , "application/vnd.adobe.xdp"              },
      	{".xdr"    , "text/xml"                               },
      	{".xfd"    , "application/vnd.adobe.xfd"              },
      	{".xfdf"   , "application/vnd.adobe.xfdf"             },
      	{".xhtml"  , "text/html"                              },
      	{".xls"    , "application/vnd.ms-excel"               },
      	{".xls"    , "application/x-xls"                      },
      	{".xlw"    , "application/x-xlw"                      },
      	{".xml"    , "text/xml"                               },
      	{".xpl"    , "audio/scpls"                            },
      	{".xq"     , "text/xml"                               },
      	{".xql"    , "text/xml"                               },
      	{".xquery" , "text/xml"                               },
      	{".xsd"    , "text/xml"                               },
      	{".xsl"    , "text/xml"                               },
      	{".xslt"   , "text/xml"                               },
      	{".xwd"    , "application/x-xwd"                      },
      	{".x_b"    , "application/x-x_b"                      },
      	{".x_t"    , "application/x-x_t"                      }
      };
      
      #endif // _MIME_H
      
    2. resource.h

      #ifndef _RESOURCE_H
      #define _RESOURCE_H
      
      // Search resource
      int searchResource(char const* path);
      
      // Identify type
      int identifyType(char const* path, char* type);
      #endif
      
    3. resource.c

      #include <stdio.h>
      #include <string.h>
      #include <unistd.h>
      #include <sys/syscall.h>
      #include "resource.h"
      #include "mime.h"
      
      // Search resource
      int searchResource(char const* path){
      	return access(path, R_OK);
      }
      
      // Identify type
      int identifyType(char const* path, char* type){
      	char* suffix = strchr(path, '.');
      	if (suffix == NULL){
      		printf("Process:%d. Thread:%ld>>>>>> Can not get the file extension.\n", getpid(), syscall(SYS_gettid));
      		return -1;
      	}
      
      	for(size_t i =0; i<sizeof(s_mime)/sizeof(s_mime[0]); i++){
      		if (!strcasecmp(suffix, s_mime[i].suffix)){
      			strcpy(type, s_mime[i].type);
      			return 0;
      		}
      	}
      
      	printf("Process:%d. Thread:%ld>>>>>> Unable to parse resource type: %s.\n", getpid(), syscall(SYS_gettid), suffix);
      	return -1;
      }
      
  3. Socket Module

    1. socket.h

      #ifndef _SOCKET_H
      #define _SOCKET_H
      
      // Initialize socket
      int initSocket(short port);
      
      // Accept client connect
      int acceptClient(void);
      
      // Accept request
      char* recvRequest(int conn);
      
      // Send respond head
      int sendHead(int conn, char const* head);
      
      // Send respond body
      int sendBody(int conn, char const* path);
      
      // Terminate socket
      void terminateSocket(void);
      
      #endif
      
    2. socket.c

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <pthread.h>
      #include <sys/resource.h>
      #include "server.h"
      #include "signals.h"
      #include "client.h"
      #include "socket.h"
      
      // Initialize the maximum number of the files
      static int initMaxFiles(void){
      	// Resource limit struct
      	struct rlimit rl;
      
      	// Get current process maximum file descriptor number
      	if (getrlimit(RLIMIT_NOFILE, &rl) == -1){
      		perror("getlimit");
      		return -1;
      	}
      
      	// if current the maximum file descriptor number of the current process does not reach the maximum limit then
      	if (rl.rlim_cur < rl.rlim_max){
      		// set the limit to max
      		rl.rlim_cur = rl.rlim_max;
      
      		if (setrlimit(RLIMIT_NOFILE, &rl) == -1){
      			perror("setrlimit");
      			return -1;
      		}
      	}
      	return 0;
      }
      
      // Initialize server
      int initServer(short port){
      	// Initialize the maximum number of the files
      	if (initMaxFiles() == -1){
      		return -1;
      	}
      
      	// Initialize signals
      	if (initSignals() == -1){
      		return -1;
      	}
      
      	// Initialize socket
      	if (initSocket(port) == -1){
      		return -1;
      	}
      	return 0;
      }
      
      // Run server
      int runServer(char const* home){
      	for( ; ; ){
      		// Accept client connection
      		int conn = acceptClient();
      		if (conn == -1){
      			return -1;
      		}
      
      		// Client handle
      		pthread_t tid;
      		pthread_attr_t attr; // thread attribute
      		pthread_attr_init(&attr);
      		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // set detach state
      		CA* ca = (CA*)malloc(sizeof(CA));
      		ca->home = home;
      		ca->conn = conn;
      		int error = pthread_create(&tid, &attr, client, ca);
      		if (error){
      			printf("Pthread create: %s.\n", strerror(error));
      			return -1;
      		}
      	}
      	return 0;
      }
      
      // Terminate server
      int terminateServer(void){
      	// Terminate socket
      	terminateSocket();
      	return 0;
      }
      
  4. Thread Module

    1. client.h

      #ifndef _CLIENT_H
      #define _CLIENT_H
      
      // Client parameter
      typedef struct tag_ClientArgs{
      	char const* home;
      	int conn;
      } CA;
      
      // Client
      void* client(void* arg);
      
      #endif
      
    2. client.c

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <sys/stat.h>
      #include <sys/syscall.h>
      #include "client.h"
      #include "socket.h"
      #include "http.h"
      #include "resource.h"
      
      // Client
      void* client(void* arg){
      	CA* ca = (CA*)arg;
      	printf("Process:%d. Thread:%ld>>>>>> Client start.\n", getpid(), syscall(SYS_gettid));
      
      	for( ; ; ){
      		printf("--------------------------------------------------------------------------------------------------\n");
      
      		printf("Process:%d. Thread:%ld>>>>>> Recieve the request.\n", getpid(), syscall(SYS_gettid));
      
      		char* req = recvRequest(ca->conn);
      		if (req == NULL) break;
      
      		printf("Process:%d. Thread:%ld>>>>>> Request body\n\n%s", getpid(), syscall(SYS_gettid), req);
      
      		printf("Process:%d. Thread:%ld>>>>>> Parse the request.\n", getpid(), syscall(SYS_gettid));
      		// Parse request
      		HTTP_REQUEST hreq = {};
      		if (parseRequest(req, &hreq) == -1){
      			free(req);
      			break;
      		}
      
      		free(req);
      
      		// Resource request
      		char path[PATH_MAX+1];
      		strcpy(path, ca->home);
      		if (path[strlen(path)-1] == '/') path[strlen(path)-1] = '\0';
      		strcat(path, hreq.path);
      		if (!strcpy(hreq.path, "/")) strcat(path, "index.html");
      
      		printf("Process:%d. Thread:%ld>>>>>> Resource path: %s.\n", getpid(), syscall(SYS_gettid), path);
      
      		// Search resource
      		HTTP_RESPOND hres = {"HTTP/1.1", 200, "OK", "text/html"};
      		if (searchResource(path) == -1){
      			hres.status = 404;
      			strcpy(hres.description, "Not Found");
      			strcpy(path, "../Webserver_Home/404.html");
      		} else if (identifyType(path, hres.type) == -1){
      			hres.status = 404;
      			strcpy(hres.description, "Not Found");
      			strcpy(path, "../Webserver_Home/404.html");
      		}
      
      		struct stat st;
      		if (stat(path, &st) == -1){
      			perror("stat");
      			break;
      		}
      		hres.length = st.st_size;
      
      		if (strlen(hreq.connection)) strcpy(hres.connection, hreq.connection); 
      		else {
      			if (!strcasecmp(hreq.protocol, "HTTP/1.0")) strcpy(hres.connection, "close");
      			else strcpy(hres.connection, "keep-alive");
      		}
      
      		// Construct respond head
      		char head[1024];
      		constructHead(&hres, head);
      
      		printf("Process:%d. Thread:%ld>>>>>> Respond head.\n\n%s", getpid(), syscall(SYS_gettid), head);
      
      		printf("Process:%d. Thread:%ld>>>>>> Send respond.\n", getpid(), syscall(SYS_gettid));
      
      		// Send respond head
      		if (sendHead(ca->conn, head) == -1) break;
      
      		if (sendBody(ca->conn, path) == -1) break;
      
      		if (!strcasecmp(hres.connection, "close")) break;
      	}
      
      	close(ca->conn);
      	free(ca);
      	printf("Process:%d. Thread:%ld>>>>>> Client closed.\n", getpid(), syscall(SYS_gettid));
      
      	return NULL;
      }
      
  5. Signal Module

    1. signals.h

      #ifndef _SIGNALS_H
      #define _SIGNALS_H
      
      // Initialize signal
      int initSignals(void);
      
      #endif
      
    2. signals.c

      #include <stdio.h>
      #include <unistd.h>
      #include <signal.h>
      #include "signals.h"
      
      // Initialize signal
      int initSignals(void){
      	printf("Process:%d>>>>>> Ignore most of the signals.\n", getpid());
      
      	for(int signum = 1; signum <= 64; ++signum){
      		if (signum != SIGINT && signum != SIGTERM) signal(signum, SIG_IGN);   
      	}
      	return 0;
      }
      
  6. Server Module

    1. server.h

      #ifndef _SERVER_H
      #define _SERVER_H
      
      // Initialize server
      int initServer(short port);
      
      // Run server
      int runServer(char const* home);
      
      // Terminate server
      int terminateServer(void);
      
      #endif
      
    2. server.c

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <pthread.h>
      #include <sys/resource.h>
      #include "server.h"
      #include "signals.h"
      #include "client.h"
      #include "socket.h"
      
      // Initialize the maximum number of the files
      static int initMaxFiles(void){
      	// Resource limit struct
      	struct rlimit rl;
      
      	// Get current process maximum file descriptor number
      	if (getrlimit(RLIMIT_NOFILE, &rl) == -1){
      		perror("getlimit");
      		return -1;
      	}
      
      	// if current the maximum file descriptor number of the current process does not reach the maximum limit then
      	if (rl.rlim_cur < rl.rlim_max){
      		// set the limit to max
      		rl.rlim_cur = rl.rlim_max;
      
      		if (setrlimit(RLIMIT_NOFILE, &rl) == -1){
      			perror("setrlimit");
      			return -1;
      		}
      	}
      	return 0;
      }
      
      // Initialize server
      int initServer(short port){
      	// Initialize the maximum number of the files
      	if (initMaxFiles() == -1){
      		return -1;
      	}
      
      	// Initialize signals
      	if (initSignals() == -1){
      		return -1;
      	}
      
      	// Initialize socket
      	if (initSocket(port) == -1){
      		return -1;
      	}
      	return 0;
      }
      
      // Run server
      int runServer(char const* home){
      	for( ; ; ){
      		// Accept client connection
      		int conn = acceptClient();
      		if (conn == -1){
      			return -1;
      		}
      
      		// Client handle
      		pthread_t tid;
      		pthread_attr_t attr; // thread attribute
      		pthread_attr_init(&attr);
      		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // set detach state
      		CA* ca = (CA*)malloc(sizeof(CA));
      		ca->home = home;
      		ca->conn = conn;
      		int error = pthread_create(&tid, &attr, client, ca);
      		if (error){
      			printf("Pthread create: %s.\n", strerror(error));
      			return -1;
      		}
      	}
      	return 0;
      }
      
      // Terminate server
      int terminateServer(void){
      	// Terminate socket
      	terminateSocket();
      	return 0;
      }
      
  7. Main Module

    1. main.c

      #include <stdio.h>
      #include <stdlib.h>
      #include "server.h"
      
      int main(int argc, char* argv[]){
      	// Initialize server
      	if (initServer(argc < 2 ? 8000 : atoi(argv[1])) == -1){
      		return EXIT_FAILURE;
      	}
      
      	// Run server
      	if (runServer(argc < 3 ? "./../Webserver_Home" : argv[2]) == -1){
      		return EXIT_FAILURE;
      	}
      
      	// Terminate server
      	return EXIT_SUCCESS;
      }
      
  8. Makefile

    PROJ   = WebServer
    OBJS   = main.o server.o signals.o socket.o client.o http.o resource.o
    CC     = gcc
    LINK   = gcc
    RM     = rm -rf
    CFLAGS = -c -Wall -I.
    LIBS   = -lpthread
    
    $(PROJ): $(OBJS)
    	$(LINK) $^ $(LIBS) -o $@
    
    .c.o:
    	$(CC) $(CFLAGS) $^ -o $@
    
    clean:
    	$(RM) $(PROJ) $(OBJS)
    

GitHub: https://github.com/2790004z/Linux_WebServer_C_Language.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1.下载并安装rtsp-simple-server 您可以从https://github.com/aler9/rtsp-simple-server/releases 下载适用于您的操作系统的rtsp-simple-server。 对于Ubuntu或Debian用户,可以使用以下命令下载和安装: ``` wget https://github.com/aler9/rtsp-simple-server/releases/download/v0.17.2/rtsp-simple-server_v0.17.2_linux_amd64.tar.gz tar -xzvf rtsp-simple-server_v0.17.2_linux_amd64.tar.gz cd rtsp-simple-server_v0.17.2_linux_amd64 sudo cp rtsp-simple-server /usr/local/bin/ ``` 2. 启动rtsp-simple-server 在终端中执行以下命令以启动rtsp-simple-server: ``` rtsp-simple-server ``` 这将会启动rtsp-simple-server并在终端输出日志信息。 默认情况下,rtsp-simple-server 监听所有网卡上的 8554 端口。如果您需要更改端口号,可以使用以下命令: ``` rtsp-simple-server --rtsp-port=[PORT_NUMBER] ``` 3. 使用rtsp-simple-server 启动rtsp-simple-server后,您可以通过网络独立地连接和使用RTSP流,并将其传输到其他客户端。 例如,您可以使用VLC打开RTSP连接并查看视频流: - 启动VLC并选择“文件”>“打开网络...” - 在“URL”字段中输入:rtsp://[RTSP_SERVER_IP]:8554/stream - 点击“播放”并等待视频流的加载。 请确保替换 [RTSP_SERVER_IP] 为rtsp-simple-server所在的IP地址。 4. 指定视频源 rtsp-simple-server需要知道视频从哪里流入,因此您需要指定一个或多个输入源。 您可以使用以下命令启动示例源进行测试: ``` rtsp-simple-server --rtsp-port=8554 --publish-tester-video ``` 此命令将使用测试视频建立一个默认的rtsp://localhost:8554/stream输入源。 您还可以将自己的数据流作为输入源传输到rtsp-simple-server,例如: - 使用ffmpeg将视频文件流式传输到rtsp-simple-server ``` ffmpeg -re -i [LOCAL_VIDEO_FILE] -f rtsp rtsp://[RTSP_SERVER_IP]:8554/stream ``` - 使用 gstreamer 将相机视频流传输到 rtsp-simple-server。 ``` gst-launch-1.0 v4l2src ! videoconvert ! x264enc tune=zerolatency ! rtph264pay ! udpsink host=[RTSP_SERVER_IP] port=8554 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值