徒手撸个http服务器(一)

Linux-c http server

HTTP协议

HTTP(HyperText Transfer Protocol)协议是一个应用层协议,这个协议定义了运行在不同段系统上的应用程序进程如何相互传递报文.

该协议还定义了:

  • 交换的报文类型,例如请求报文和响应报文.
  • 各种报文类型的语法,如报文中各个字段及这些字段是如何描述的.
  • 字段的语义,即这些字段中包含的信息的含义.
  • 一个进程何时以及如何发送报文,对报文进行响应的规则.

HTTP链接过程

HTTP使用TCP作为它的支撑运输协议.HTTP客户端首先发起一个与服务器的TCP链接(过程参考TCP三次握手).一旦建立连接,浏览器和服务器进程就可以通过套接字接口访问TCP.这样客户就可以向它的套接字接口发送HTTP请求报文并从它的套接字接口接收HTTP报文响应.类似地,服务器也从它的套接字接口接收HTTP请求报文和向它的套接字接口发送HTTP响应报文.

HTTP报文

典型请求报文

GET /somedir/page.html HTTP/1.1
Host: localhost:8080
Connection: keep-alive
User-Agent: Mozilla/5.0 
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4

该报文由5行组成,每行由一个回车和一个换行符结束.最后再加一个回车换行符.

第一行叫请求行, 其余后继行叫首部行,请求行包括方法字段,URL字段和HTTP版本字段.方法字段可以取GET, POST, HEAD, PUT和DELETE这几个不同的值.

本例中,该浏览器正在请求对象/somedir/page.html.
(剩下的几行..对这个玩具服务器不重要)

典型响应报文

HTTP/1.1 200 OK
Connection: close
Data: Tue, 09 Aug 2333 23:33:33 GMT
Server: MyServer/2.3.3 (DebianOS)
Content-Type: text/html

(data data data data ...)

第一行,初始状态行,下面四行叫首部行, 然后是实体体, 实体体部分是报文的主要部分.

状态行有3个字段: 协议版本字段, 状态码和相应状态信息.本例中,状态行指示服务器正在使用HTTP/1.1, 并且一切正常.

接下来看看首部行,Connection: close告诉客户端, 发送完报文后将关闭该TCP连接, Date 指示时间, Server 指示该报文是由一个玩具服务器发出的… Content-Type 指示了实体体中对象是HTML文本.

开撸

这个服务器使用多进程处理不同的连接.下次用epoll()好了..

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXQUE 1024

// 杀掉僵死进程
void kill_chil(int sig)
{
    int status;
    pid_t pi;
    while((pi = waitpid(-1, &status, WNOHANG)) > 0) {
        printf("killed childpid %d\n", pi);
    }
    return ;
}

// 不管什么请求都发送这个页面好了...
void handle_this(int fileno)
{
    char buff[4096];
    char head[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\nServer: MyServer/2.3.3 (DebianOS)\r\n\r\n";
    char send[] = "test

This is a Dome Server!!

"
; //memset(buff, 0, sizeof(buff)); read(fileno, buff, 4096); write(fileno, head, sizeof(head)); write(fileno, send, sizeof(send)); printf("%s", buff); } int main(void) { int servfd, connfd; pid_t childpid; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8080); servfd = socket(AF_INET, SOCK_STREAM, 0); bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(servfd, MAXQUE); void (*handle)(int); handle = kill_chil; signal(SIGCHLD, handle); while(1) { socklen_t socklen = sizeof(servaddr); if((connfd = accept(servfd, (struct sockaddr *)&servaddr, &socklen)) < 0) { if(errno == EINTR) { printf("[ Error ] Accept Error!\n"); exit(-1); } else { continue; } } if((childpid = fork()) == 0) { // 子进程处理连接 close(servfd); handle_this(connfd); exit(0); } else { close(connfd); } } return 0; }

看起来还行…

徒手撸个http服务器(一)_第1张图片

你可能感兴趣的:(好玩的,http服务器,应用,linux-c)