关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

Http协议,web服务器,并发服务器

发布时间:2021-04-19 16:19:36

一、HTTP协议介绍

1.使用谷歌/火狐浏览器分析

在Web应用中,服务器将网页发送给浏览器,浏览器实际上是将网页的HTML代码发送给浏览器供浏览器显示。而浏览器和服务器之间的传输协议是HTTP,所以:


HTML是一种用来定义网页的文本。如果你知道超文本标记语言,你可以写网页;


HTTP是一种通过网络传输HTML的协议,用于浏览器和服务器之间的通信。


Chrome浏览器提供了一套完整的调试工具,非常适合Web开发。


安装Chrome浏览器后,打开Chrome并从菜单中选择视图、开发人员和开发人员工具,以显示开发人员工具:




解释

元素显示网页的结构

网络显示浏览器和服务器之间的通信

让我们点击Network,确定第一个小红灯亮了,Chrome会记录所有浏览器和服务器之间的通信:




2.HTTP协议分析

当我们在地址栏输入www.sina.com时,浏览器会显示新浪的主页。浏览器在这个过程中做了什么?从网络的记录中,我们可以知道。在网络中,找到www.sina.com的记录,单击它,请求标题将显示在右侧。点击右侧的查看来源,可以看到浏览器发送给新浪服务器的请求:


2.1浏览器请求

解释

主要前两行分析如下,第一行:


GET / HTTP/1.1

GET表示读取请求,会从服务器获取网页数据,/表示URL的路径,URL始终以/开头,/表示第一页,最后一个HTTP/1.1表示采用的HTTP协议版本是1.1。目前HTTP协议的版本是1.1,但是大部分服务器也支持1.0版本。主要区别是1.1版允许多个HTTP请求重用一个TCP连接来加快传输速度。


从第二行开始,每一行都类似于Xxx: abcdefg:


主持人:www.sina.com

表示请求的域名是www.sina.com。如果一个服务器有多个网站,服务器需要通过Host来区分浏览器请求的是哪个网站。


2.2服务器响应

继续查找响应头,单击查看源,并显示服务器返回的原始响应数据:


HTTP响应分为报头和正文(正文可选)。我们在网络中看到的最重要的标题行如下:


HTTP/1.1 200 OK



200表示响应成功,以下OK为解释。


如果返回值不是200,那么通常还有其他函数,比如


失败的响应是404未找到:网页不存在

500内部服务器错误:内部服务器错误

...等等...

内容类型:文本/html

内容类型表示响应的内容,其中文本/超文本标记语言表示超文本标记语言网页。


请注意,浏览器依赖内容类型来判断响应内容是网页还是图片、视频或音乐。浏览器并不依靠网址来判断回复的内容,所以即使网址是http://www.baidu.com/meimei.jpg,,也不一定是图片。


HTTP响应的正文是HTML源代码。我们可以通过选择菜单栏中的“查看”、“开发人员”和“查看网页源代码”,直接在浏览器中查看HTML源代码:




浏览器解析过程

浏览器在读取新浪首页HTML源代码时,会解析HTML并显示页面。然后根据HTML中的各种链接,向新浪服务器发送HTTP请求,获取相应的图片、视频、Flash、JavaScript脚本、CSS等资源,最后显示完整的页面。所以我们可以看到网络下有很多额外的HTTP请求。




3.总结

3.1 HTTP请求

追踪新浪首页,我们来总结一下HTTP请求的流程:


3.1.1步骤1:浏览器首先向服务器发送HTTP请求,包括:

方法:GET或POST,GET只请求资源,POST会伴随用户数据;


路径:/full/URL/path;


域名:由主机标题指定:主机:www.sina.com


和其他相关标题;;


如果是开机自检,请求还包括一个包含用户数据的正文


3.1.1步骤2:服务器向浏览器返回一个HTTP响应,包括:

响应码:200表示成功,3xx表示重定向,4xx表示客户端发送的请求有错误,5xx表示服务器在处理过程中有错误;


响应类型:由内容类型指定;


和其他相关标题;;


通常服务器的HTTP响应都带有内容,也就是有一个Body包含响应的内容,网页的HTML源代码在Body中。


3.1.1步骤3:如果浏览器需要继续向服务器请求其他资源,比如图片,会再次发送HTTP请求,重复步骤1和2。

Web采用的HTTP协议采用了非常简单的请求-响应模式,大大简化了开发。我们写页面的时候,只需要在HTTP请求中发送HTML,不考虑如何附上图片和视频。如果浏览器需要请求图片和视频,会再发送一个HTTP请求。所以一个HTTP请求只处理一个资源(此时可以理解为TCP协议中的短连接,每个链路只得到一个资源。如果需要多个链接,则需要建立多个链接)


HTTP协议同时具有很强的扩展性。虽然浏览器请求的是http://www.sina.com的主页,但新浪可以用HTML等方式链接其他服务器的资源,将请求压力分散到各个服务器上。而且一个站点可以链接到其他站点,无数个站点相互链接,从而形成了万维网。




3.2 HTTP格式

每个HTTP请求和响应遵循相同的格式,一个HTTP包含头和体,其中体是可选的。


HTTP协议是文本协议,所以格式也很简单。


3 . 2 . 1 http get请求格式:

GET /path HTTP/1.1

标题1:值1

标题2:值2

标题3:值3



每个Header都有一行,换行符是\ r \ n


3 . 2 . 2 http post请求的格式:

POST /path HTTP/1.1

标题1:值1

标题2:值2

标题3:值3


身体数据在这里...



当遇到两个连续的\ r \ ns时,标题部分结束,后面的数据全部是正文。


3 . 2 . 3 http响应的格式:

200 OK

标题1:值1

标题2:值2

标题3:值3


身体数据在这里...



如果HTTP响应包含正文,它也用\ r \ n \ r \ n分隔。


请再次注意,正文的数据类型由内容类型标题决定。如果是网页,Body就是文本,如果是图片,Body就是图片的二进制数据。


当有内容编码时,正文数据被压缩,最常见的压缩方法是gzip。所以,当你看到Content-Encoding: gzip的时候,你需要对Body数据进行解压缩,才能得到真实的数据。压缩的目的是减小Body的大小,加快网络传输速度。


二.网络静态服务器-1-显示固定页面

#coding=utf-8

导入套接字



def句柄_客户端(client_socket):

“为客户服务”

recv _ data = client _ socket . recv(1024)。解码(“utf-8”)

request _ header _ lines = recv _ data . split lines()

对于请求标题行中的行:

打印(行)


#组织相应的标题信息(标题)

response _ headers = " http/1.1 200 ok \ r \ n " # 200表示找到了此资源

response_headers += "\r\n" #与正文之间用一个空行隔开

#组织内容(正文)

response_body = "hello world "


response = response _ headers+response _ body

client _ socket . send(response . encode(" utf-8 "))

client_socket.close()



def main():

“作为程序的主要控制项”


server _ socket = socket . socket(socket。AF_INET,socket。SOCK_STREAM)

#设置在服务器先关闭的时候,也就是服务器波动4次之后可以立即释放资源,保证下次运行程序的时候可以立即绑定7788端口

server _ socket . setsockopt(socket。SOL_SOCKET,SOCKET。SO_REUSEADDR,1)

server_socket.bind((" ",7788))

server_socket.listen(128)

而真实:

client_socket,client _ addr = server _ socket . accept()

handle_client(client_socket)



if __name__ == "__main__ ":

main()



三.网络静态服务器-2-显示所需页面

#coding=utf-8

导入套接字

进口re



def句柄_客户端(client_socket):

“为客户服务”

recv _ data = client _ socket . recv(1024)。解码(' utf-8 ',错误=“忽略”)

request _ header _ lines = recv _ data . split lines()

对于请求标题行中的行:

打印(行)


http _ request _ line = request _ header _ lines[0]

get _ file _ name = re.match("[^/]+(/[^]*)”,http_request_line)。组(1)

打印(文件名= = = > % s“% get _ file _ name”)#进行测试


#如果您没有指定要访问哪个页面。例如,index.html

# GET / HTTP/1.1

如果get_file_name == "/:

get _ FIle _ name = DOCUMENTS _ ROOT+"/index . html "

else:

get _ FIle _ name = DOCUMENTS _ ROOT+get _ FIle _ name


打印(文件名= = = 2 > % s“% get _ file _ name”)#进行测试


尝试:

f =打开(get_file_name,“rb”)

除了IOError:

# 404表示没有这样的页面

response_headers = "未找到HTTP/1.1 404 \ r \ n "

response_headers += "\r\n "

response _ body ====抱歉,找不到文件= = = = "

else:

response _ headers = " HTTP/1.1 200 OK \ r \ n "

response_headers += "\r\n "

response_body = f.read()

f.close()

最后:

#由于表头信息在组织时是按字符串组织的,无法与二进制打开文件读取的数据合并,所以单独发送。

#首先发送响应的报头信息

client _ socket . send(response _ headers . encode(' utf-8 '))

#再次发送正文

client _ socket . send(response _ body)

client_socket.close()



def main():

“作为程序的主要控制项”

server _ socket = socket . socket(socket。AF_INET,socket。SOCK_STREAM)

server _ socket . setsockopt(socket。SOL_SOCKET,SOCKET。SO_REUSEADDR,1)

server_socket.bind((" ",7788))

server_socket.listen(128)

虽然真实:

client_socket,clien _ cAddr = server _ socket . accept()

handle_client(client_socket)



#在此配置服务器

DOCUMENTS_ROOT = "。/html "


if __name__ == "__main__ ":

main()




四.网络静态服务器-3-多进程

#coding=utf-8

导入套接字

进口re

导入多重处理



WSGIServer类(对象):


def __init__(self,server_address):

#创建tcp套接字

self . listen _ socket = socket . socket(socket。AF_INET,socket。SOCK_STREAM)

#允许立即使用最后一个绑定端口

self . listen _ socket . setsockopt(socket。SOL_SOCKET,SOCKET。SO_REUSEADDR,1)

#绑定

self . listen _ socket . bind(server _ address)

#变得被动并设置队列长度

self.listen_socket.listen(128)


def serve _ every(self):

"循环运行网络服务器,等待客户链接,为客户服务. "

而真实:

#等待新客户的到来

client_socket,client _ address = self . listen _ socket . accept()

打印(客户端地址)#用于测试

new_process =多重处理。进程(目标=self.handleRequest,args=(client_socket,)

new_process.start()


#因为子进程已经复制了父进程的套接字和其他资源,所以调用close的父进程不会关闭它们相应的链接

client_socket.close()


def handleRequest(自身,客户端套接字):

"使用新的流程为客户服务."

recv _ data = client _ socket . recv(1024)。解码(' utf-8 ')

打印(recv_data)

requestHeaderLines = recv _ data . split lines()

对于requestHeaderLines中的行:

打印(行)


request _ line = RequestHeaderlines[0]

get _ file _ name = re.match("[^/]+(/[^]*)”,request_line)。组(1)

打印(文件名= = = > % s“% get _ file _ name”)#进行测试


如果get_file_name == "/:

get _ FIle _ name = DOCUMENTS _ ROOT+"/index . html "

else:

get _ FIle _ name = DOCUMENTS _ ROOT+get _ FIle _ name


打印(文件名= = = 2 > % s“% get _ file _ name”)#进行测试


尝试:

f =打开(get_file_name,“rb”)

除了IOError:

response_header = "未找到HTTP/1.1 404 \ r \ n "

response_header += "\r\n "

response _ body ====抱歉,找不到文件= = = = "

else:

response _ header = " HTTP/1.1 200 OK \ r \ n "

response_header += "\r\n "

response_body = f.read()

f.close()

最后:

client _ socket . send(response _ header . encode(' utf-8 '))

client _ socket . send(response _ body)

client_socket.close()



#设置服务器的端口

服务器_ADDR =(主机,端口)= ",8888

#设置服务器服务的静态资源时的路径

DOCUMENTS_ROOT = "。/html "



def main():

httpd = WSGIServer(服务器_ADDR)

打印(“网络服务器:在端口%d上提供HTTP...\ n“% PORT”)

httpd . serve _ every()


if __name__ == "__main__ ":

main()



动词 (verb的缩写)Web静态服务器-4-多线程

#coding=utf-8

导入套接字

进口re

导入线程



WSGIServer类(对象):


def __init__(self,server_address):

#创建tcp套接字

self . listen _ socket = socket . socket(socket。AF_INET,socket。SOCK_STREAM)

#允许立即使用最后一个绑定端口

self . listen _ socket . setsockopt(socket。SOL_SOCKET,SOCKET。SO_REUSEADDR,1)

#绑定

self . listen _ socket . bind(server _ address)

#变得被动并设置队列长度

self.listen_socket.listen(128)


def serve _ every(self):

"循环运行网络服务器,等待客户链接,为客户服务. "

虽然真实:

#等待新客户的到来

client_socket,client _ address = self . listen _ socket . accept()

打印(客户端地址)

new_process = threading。thread(target = self . handlerequest,args=(client_socket,)

new_process.start()


#因为线程共享同一个套接字,所以主线程不能关闭,否则子线程不能再使用这个套接字。

# client_socket.close()


def handleRequest(自身,客户端套接字):

"使用新的流程为客户服务."

recv _ data = client _ socket . recv(1024)。解码(' utf-8 ')

打印(recv_data)

requestHeaderLines = recv _ data . split lines()

对于requestHeaderLines中的行:

打印(行)


request _ line = RequestHeaderlines[0]

get _ file _ name = re.match("[^/]+(/[^]*)”,request_line)。组(1)

打印(文件名= = = > % s“% get _ file _ name”)#进行测试


如果get_file_name == "/:

get _ FIle _ name = DOCUMENTS _ ROOT+"/index . html "

else:

get _ FIle _ name = DOCUMENTS _ ROOT+get _ FIle _ name


打印(文件名= = = 2 > % s“% get _ file _ name”)#进行测试


尝试:

f =打开(get_file_name,“rb”)

除了IOError:

response_header = "未找到HTTP/1.1 404 \ r \ n "

response_header += "\r\n "

response _ body ====抱歉,找不到文件= = = = "

else:

response _ header = " HTTP/1.1 200 OK \ r \ n "

response_header += "\r\n "

response_body = f.read()

f.close()

最后:

client _ socket . send(response _ header . encode(' utf-8 '))

client _ socket . send(response _ body)

client_socket.close()



#设置服务器的端口

服务器_ADDR =(主机,端口)= ",8888

#设置服务器服务的静态资源时的路径

DOCUMENTS_ROOT = "。/html "



def main():

httpd = WSGIServer(服务器_ADDR)

打印(“网络服务器:在端口%d上提供HTTP...\ n“% PORT”)

httpd . serve _ every()


if __name__ == "__main__ ":

main()



/template/Home/Zkeys/PC/Static