c语言实现简单web服务器

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

1http简单介绍

http超文本传输协议:host主机地址:port端口/url

host会被DNS服务器 解析成IP地址,所以有时候可以直接用域名,

http默认访问80端口,https默认访问443端口


大致流程就是:浏览器输入地址后,首先和web服务器建立tcp连接,

然后浏览器发送http请求报文, web服务器响应处理这个报文,

然后给他回复一个响应,然后服务器主动断开连接。





2http请求报文格式

)ODW3H_KT)`8D7EQ$D`F(2O.png


首先第一个就是请求的方法,方法有一下这些:
GET,POST,HEAD,PUT,DELETE,OPTIONS,TRACE,CONNECT;


1GET

在浏览器输入的网址,浏览器就会发送GET的http报文请求。

如果不写url 默认就是 "/"  服务器 可根据这个响应对应的页面.

头部信息就包含一些重要的请求信息,如主机地址.

浏览器版本 , 手机的页面就是根据这个去做的.

GET 携带参数是在url里面的, POST是携带在包体里面的.

包体成为body,请求头部叫做head。

GET传递参数,格式  /url?username=xxx&passwd=bbb  通过问号解析参数部分

url的传递参数是有限制的,每个浏览器限制都不一样。url不允许有回车换行



2POST 

POST也是一个请求操作,他的数据参数携带在http请求的body里面。

所有的参数都不允许有回车换行的存在, 很多时候如果必须要携带

回车换行的话,必须先把数据转换成base64编码,因为它没有回车换成.他是解决网络传输的常用方法。





3http响应报文格式

%R9()7K(ZWIVRRDUFFCXC[V.png


1状态码:请求是否成功,状态码描述:成功或失败的原因

有时候访问一网页 会出现404,这个404就是这个状态码.




4http数据传输模式

1传输中两个重要的参数: 写在头里面

transfer-encoding:identity,chunked表示当前这个body是什么协议发过来的

content-length:length:数据包的长度



2identity 直接发送模式,length在后面表示数据长度


3chunked 模式,后面跟的是每一个chunk包 [包头,包数据]

包头:第一个字节表示一个ASSIC数据,第二个字节也是ASSIC数据

两个字节加起来,组成一个16进制数据。

后面两个字节,固定的0d0a(回车换行符)两个字节这4个字节就是一个chunk的包头,

后面的数据包 根据前面的两个字节来决定。数据包的结束标志是

30  0d  0a  30ascll码代表的是0

也就是说chunk包的结束:是遇到一个为等于0的chunk结束。

然后把这个包整合一下,形成完整的数据。





5http状态码和表

/*

{

[100] = "Continue",

[101] = "Switching Protocols",

[200] = "OK",

[201] = "Created",

[202] = "Accepted",

[203] = "Non-Authoritative Information",

[204] = "No Content",

[205] = "Reset Content",

[206] = "Partial Content",

[300] = "Multiple Choices",

[301] = "Moved Permanently",

[302] = "Found",

[303] = "See Other",

[304] = "Not Modified",

[305] = "Use Proxy",

[307] = "Temporary Redirect",

[400] = "Bad Request",

[401] = "Unauthorized",

[402] = "Payment Required",

[403] = "Forbidden",

[404] = "Not Found",

[405] = "Method Not Allowed",

[406] = "Not Acceptable",

[407] = "Proxy Authentication Required",

[408] = "Request Time-out",

[409] = "Conflict",

[410] = "Gone",

[411] = "Length Required",

[412] = "Precondition Failed",

[413] = "Request Entity Too Large",

[414] = "Request-URI Too Large",

[415] = "Unsupported Media Type",

[416] = "Requested range not satisfiable",

[417] = "Expectation Failed",

[500] = "Internal Server Error",

[501] = "Not Implemented",

[502] = "Bad Gateway",

[503] = "Service Unavailable",

[504] = "Gateway Time-out",

[505] = "HTTP Version not supported",

}

*/





6使用http_parmer解析 URL读取 然后返回给客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//解析我们的http报文
http_parser p;
http_parser_init(&p,HTTP_REQUEST);
http_parser_settings s;
http_parser_settings_init(&s);
//解析到了url 回调
s.on_url = ws_on_url;
//重置解析信息
init_ws_params();
// 解析器执行。返回解析的字节数
http_parser_execute(&p,&s,http_req,len);
//设置回调函数
switch  (p.method)   //报文响应的方式
{
case  HTTP_GET:
{
int  len_URL = filter_url(WS_HTTP.url);
//访问的网页  
if  ( strncmp ( "/" , WS_HTTP.url, len_URL) == 0){  //访问test这个html
strncpy (WS_HTTP.url,  "www_root/index.html" strlen ( "www_root/index.html" ));
}
else  if  ( strncmp ( "/test" , WS_HTTP.url, len_URL) == 0){  //访问默认的url 根目录
strncpy (WS_HTTP.url,  "www_root/test.html" strlen ( "www_root/test.html" ));
}
char * file_data = open_files(WS_HTTP.url);
//发送报文  也就是响应客户端
//释放内存
free (file_data);
}
break ;
case  HTTP_POST:
break ;
}
//end
printf ( "\n" );
 
 
读取文件
static  char
open_files( char * filename)
{
     //读取这个文件
     FILE * f =  fopen (filename, "rb" );
     //文件大小
     int  file_size = 0;
     fseek (f,0,SEEK_END);
     file_size =  ftell (f);
     //指针又到文件头
     fseek (f, 0, 0);
 
     char * file_data =  malloc (file_size + 1);
     fread (file_data, file_size,1, f);
     file_data[file_size] = 0;
 
 
     fclose (f);
     return  file_data;
     
}




7响应请求报文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//使用identity来发送响应报文 
static  void
write_ok_identity( int  sock,  char * body)
{
int  len =  strlen (body);
//使用直接模式 transfer-encoding:identity
char * send_line =  malloc (len + 8096);
memset (send_line, 0,  sizeof (send_line));
//回应http的头
sprintf (send_line,  "HTTP/1.1  %d %s\r\n" , 200,  "OK" );
//设置头部的一些信息  比如传送模式 body的长度
char * walk = send_line;
//跳过这个头部
walk = walk +  strlen (walk);
sprintf (walk, "transfer-encoding:%s\r\n" , "identity" );
//body的长度
walk = walk +  strlen (walk);   //头结束
sprintf (walk,  "content-length: %d\r\n\r\n0" , len);
//写入数据部分
walk = walk +  strlen (walk);
sprintf (walk,  "%s" , body);
//发送报文 响应  给客户端
send(sock, send_line,  strlen (send_line), 0);
free (send_line);
walk = NULL;
}




 本文转自超级极客51CTO博客,原文链接:http://blog.51cto.com/12158490/2059931,如需转载请自行联系原作者




相关文章
|
1月前
|
XML 前端开发 JavaScript
PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑
本文深入探讨了PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑;Ajax则通过异步请求实现页面无刷新更新。文中详细介绍了两者的工作原理、数据传输格式选择、具体实现方法及实际应用案例,如实时数据更新、表单验证与提交、动态加载内容等。同时,针对跨域问题、数据安全与性能优化提出了建议。总结指出,PHP与Ajax的结合能显著提升Web应用的效率和用户体验。
48 3
|
2月前
|
Java PHP
PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。理解其垃圾回收机制有助于开发高效稳定的PHP应用。
【10月更文挑战第1天】PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。其垃圾回收机制包括引用计数与循环垃圾回收,对提升应用性能和稳定性至关重要。本文通过具体案例分析,详细探讨PHP垃圾回收机制的工作原理,特别是如何解决循环引用问题。在PHP 8中,垃圾回收机制得到进一步优化,提高了效率和准确性。理解这些机制有助于开发高效稳定的PHP应用。
53 3
|
3月前
|
网络协议 数据处理 C语言
利用C语言基于poll实现TCP回声服务器的多路复用模型
此代码仅为示例,展示了如何基于 `poll`实现多路复用的TCP回声服务器的基本框架。在实际应用中,你可能需要对其进行扩展或修改,以满足具体的需求。
96 0
|
4月前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
212 0
|
4月前
|
Rust 安全 开发者
惊爆!Xamarin 携手机器学习,开启智能应用新纪元,个性化体验与跨平台优势完美融合大揭秘!
【8月更文挑战第31天】随着互联网的发展,Web应用对性能和安全性要求不断提高。Rust凭借卓越的性能、内存安全及丰富生态,成为构建高性能Web服务器的理想选择。本文通过一个简单示例,展示如何使用Rust和Actix-web框架搭建基本Web服务器,从创建项目到运行服务器全程指导,帮助读者领略Rust在Web后端开发中的强大能力。通过实践,读者可以体验到Rust在性能和安全性方面的优势,以及其在Web开发领域的巨大潜力。
47 0
|
4月前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
63 0
|
2天前
|
人工智能 JSON Linux
利用阿里云GPU加速服务器实现pdf转换为markdown格式
随着AI模型的发展,GPU需求日益增长,尤其是个人学习和研究。直接购置硬件成本高且更新快,建议选择阿里云等提供的GPU加速型服务器。
利用阿里云GPU加速服务器实现pdf转换为markdown格式
|
1天前
|
开发框架 缓存 .NET
阿里云轻量应用服务器、经济型e、通用算力型u1实例怎么选?区别及选择参考
在阿里云目前的活动中,价格比较优惠的云服务器有轻量应用服务器2核2G3M带宽68元1年,经济型e实例2核2G3M带宽99元1年,通用算力型u1实例2核4G5M带宽199元1年,这几个云服务器是用户关注度最高的。有的新手用户由于是初次使用阿里云服务器,对于轻量应用服务器、经济型e、通用算力型u1实例的相关性能并不是很清楚,本文为大家做个简单的介绍和对比,以供参考。
|
9天前
|
弹性计算 运维 安全
阿里云轻量应用服务器与ECS的区别及选择指南
轻量应用服务器和云服务器ECS(Elastic Compute Service)是两款颇受欢迎的产品。本文将对这两者进行详细的对比,帮助用户更好地理解它们之间的区别,并根据自身需求做出明智的选择。
|
10天前
|
SQL 弹性计算 安全
阿里云上云优选与飞天加速计划活动区别及购买云服务器后续必做功课参考
对于很多用户来说,购买云服务器通常都是通过阿里云当下的各种活动来购买,这就有必要了解这些活动的区别,同时由于活动内的云服务器购买之后还需要单独购买并挂载数据盘,还需要设置远程密码以及安全组等操作之后才能正常使用云服务器。本文就为大家介绍一下目前比较热门的上云优选与飞天加速计划两个活动的区别,以及通过活动来购买云服务器之后的一些必做功课,确保云服务器可以正常使用,以供参考。