一、http协议简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文本的传送协议。

HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

python tcp 服务端 多 python写tcp服务器_客户端

1、http协议特性

(1) 基于TCP/IP

http协议是基于TCP/IP协议之上的应用层协议。

(2) 基于请求-响应模式

HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并 返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应

python tcp 服务端 多 python写tcp服务器_HTTP_02

(3) 无状态保存

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议 自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个 级别,协议对于发送过的请求或响应都不做持久化处理。

 

 

python tcp 服务端 多 python写tcp服务器_客户端_03

使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成 如此简单的。可是,随着Web的不断发展,因无状态而导致业务处理变得棘手 的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的 其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,需要保存用户的状态。HTTP/1.1虽然是无状态协议,但为了实现期望的保持状态功能, 于是引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管 理状态了。有关Cookie的详细内容稍后讲解。

无连接

无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

2、http请求协议与响应协议

http协议包含由浏览器发送数据到服务器需要遵循的请求协议与服务器发送数据到浏览器需要遵循的请求协议。用于HTTP协议交互的信被为HTTP报文。请求端(客户端)的HTTP报文 做请求报文,响应端(服务器端)的 做响应报文。HTTP报文本身是由多行数据构成的文本。 

python tcp 服务端 多 python写tcp服务器_服务器_04

(1)请求协议

请求格式

python tcp 服务端 多 python写tcp服务器_客户端_05

请求方式: get与post请求

  • GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的请求体中.
  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
  • GET与POST请求在服务端获取请求数据方式不同。

(2)响应协议

响应格式

python tcp 服务端 多 python写tcp服务器_客户端_06

响应状态码

状态码的职责是当客户端向服务器端发送请求时, 返回的请求 结果。借助状态码,用户可以知道服务器端是正常回应了请求,还是出现了问题。状态码如200 OK,以3位数字和原因组成。数字中的 一位指定了响应级别,后两位无区分。响应分别有以5种。

python tcp 服务端 多 python写tcp服务器_客户端_07

二、使用网络助手模拟web服务器

1、Ubuntu中web服务器部署

httpd.conf的实际内容应该在etc/apache2/sites-enabled/000-default里面

(1)常见的web服务器

常见的web服务器有Apache、ngnix、IIS

 Apache

        Apache音译为阿帕奇, 是全世界最受欢迎的web服务器,因其快速、可靠并且可通过简单的API扩充,能将Python\Perl等解释器部署在其上面等优势,受到广泛的关注与使用。

 Ngnix
        Apache的致命缺陷就是在同时处理大量的(一万个以上)请求时,显得有些吃力,所以“战斗民族”的人设计的一款轻量级的web服务器——Ngnix, 在高并发下nginx 能保持比Apache低资源低消耗高性能 ,

  IIS
        iis是Internet Information Services的缩写,意为互联网信息服务,是由微软公司提供的基于运行Microsoft Windows的互联网基本服务, 

(2)Apache2 web 服务器的安装

相信学习过Linux,再加上自己的Linux版本是Ubuntu 18.04的朋友会疑惑自己的Linux系统上没有httpd这个服务,其实这一点我们不必惊慌,我们也不必单独装一个httpd服务,此时直接装一个Apache便搞定,因为httpd是Apache超文本传输协议(HTTP)服务器的主程序。被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程的池。下面我们来看看新版的Apache2 web服务器的安装:

无需华丽的修辞,我们一个命令搞定: sudo apt install apache2 -y

安装完毕后,我们检查是否启动了Apache服务:systemctl status apache2

我们再来看看一些操作Apache的常用命令(开启、关闭和重启服务器)

  • 1、/etc/init.d/apache2 start    //启动Apache服务
  • 2、/etc/init.d/apache2 stop    //停止Apache服务
  • 3、/etc/init.d/apache2 restart    //重启Apache服务

下面我们就可以开始访问我们刚刚配置的Apache服务器了。打开浏览器,输入http://127.0.0.1/ (这是主机默认的IP地址)或者如果是云主机就输入云主机的IP地址。当我们看到下面的页面时变说明Apache2 服务已经成功在我们的服务器上工作了。 

python tcp 服务端 多 python写tcp服务器_python tcp 服务端 多_08

网络调试助手简单测试:

python tcp 服务端 多 python写tcp服务器_服务器_09

浏览器发送给服务器的请求信息:

Accept-Encoding:支持的压缩格式。

python tcp 服务端 多 python写tcp服务器_客户端_10

服务器发送给浏览器的回应信息解析:

Content-Encoding:发送数据时的压缩格式

服务器发送给浏览器的数据分为两部分:头部(用于设置)和 网页具体信息,两者用一个或多个换行分隔。

python tcp 服务端 多 python写tcp服务器_python tcp 服务端 多_11

2、用户请求不同的网页改变连接时收到的数据会稍微不同

python tcp 服务端 多 python写tcp服务器_服务器_12

三、HTTP协议工作原理

HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。

以下是 HTTP 请求/响应的步骤:

1、客户端连接到Web服务器
一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.oakcms.cn。

2、发送HTTP请求
通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。

3、服务器接受请求并返回HTTP响应
Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。

4、释放连接TCP连接
若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;

5、客户端浏览器解析HTML内容
客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。

四、python服务器实现

注:返回固定页面的http服务器

import socket

def webService(new_socket):
    """为客户端返回数据"""
    #1、接收浏览器发送过来的请求,即http请求
    #GET / HTTP1.1
    request = new_socket.recv(10240)
    print(request)

    #2、返回http格式的数据给浏览器
    #2.1、准备发送给浏览器的数据 --header--
    response = "HTTP/1.1 200 OK\r\n"
    response += "\r\n" #换行
    #2.2、准备发送给浏览器的数据 --body----
    response += "<h1>hanmh_ test</h1>"
    new_socket.send(response.encode("utf-8"))

    #3、关闭套接字
    new_socket.close()


def main():
    """用来完成整体的控制"""
    #1、创建套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #2、绑定
    tcp_server_socket.bind(("", 7890))

    #3、变为监听套接字
    tcp_server_socket.listen(128)

    while True:
        #4、等待新客户端的连接
        new_socket, client_addr = tcp_server_socket.accept()

        #5、为这个客户端服务
        webService(new_socket)

    #关闭监听套接字
    tcp_server_socket.close()
    return None


if __name__ == '__main__':
    main()

python tcp 服务端 多 python写tcp服务器_服务器_13

五、返回浏览器需要的页面的HTTP服务器

import socket

#发送请求的数据文件
def webService(new_socket):
    """为客户端返回数据"""
    #1、接收浏览器发送过来的请求,即http请求
    #GET / HTTP1.1
    request = new_socket.recv(10240)
    print(request)

    #2、返回http格式的数据给浏览器
    #2.1、准备发送给浏览器的数据 --header--
    response = "HTTP/1.1 200 OK\r\n"
    response += "\r\n" #换行
    #2.2、准备发送给浏览器的数据 --body----
    f = open("./index.html", "rb")
    html_content = f.read()
    f.close()

    #2.3、将response header发送给浏览器
    new_socket.send(response.encode("utf-8"))
    #2.4、将response body发送给浏览器
    new_socket.send(html_content)

    #3、关闭套接字
    new_socket.close()


def main():
    """用来完成整体的控制"""
    #1、创建套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #2、绑定
    tcp_server_socket.bind(("", 7890))

    #3、变为监听套接字
    tcp_server_socket.listen(128)

    while True:
        #4、等待新客户端的连接
        new_socket, client_addr = tcp_server_socket.accept()

        #5、为这个客户端服务
        webService(new_socket)

    #关闭监听套接字
    tcp_server_socket.close()
    return None


if __name__ == '__main__':
    main()

python tcp 服务端 多 python写tcp服务器_python tcp 服务端 多_14

1、logo显示不了的原因

html文件中发现需要图片数据,随后浏览器就发送新的请求,用来请求图片。但是目前我们的服务器没有写这些业务。

python tcp 服务端 多 python写tcp服务器_python tcp 服务端 多_15

2、相应改进

加入了请求文件判断,若请求文件为空则返回404 not found

import re
import socket

#发送请求的数据文件
def webService(new_socket):
    """为客户端返回数据"""
    #1、接收浏览器发送过来的请求,即http请求
    #GET / HTTP1.1
    request = new_socket.recv(1024).decode("utf-8")
    request_lines = request.splitlines() #按行切割
    print("")
    print(">" * 100)
    print(request_lines)

    #提取需要的文件名
    #GET /index.html HTTP/1.1
    file_name = ""
    ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
    if ret:
        file_name = ret.group(1)
        if file_name == "/":
            file_name = "./index.html"
    else:
        return

    try:
        f = open("." + file_name, "rb")
    except:
        response = "HTTP/1.1 404 NOT FOUND\r\n"
        response += "\r\n"
        response += "-------file not found-------"
        new_socket.send(response.encode("utf-8"))
    else:
        # 2、返回http格式的数据给浏览器
        # 2.1、准备发送给浏览器的数据 --header--
        response = "HTTP/1.1 200 OK\r\n"
        response += "\r\n"  # 换行
        # 2.2、准备发送给浏览器的数据 --body----
        html_content = f.read()
        f.close()
        # 2.3、将response header发送给浏览器
        new_socket.send(response.encode("utf-8"))
        # 2.4、将response body发送给浏览器
        new_socket.send(html_content)

    #3、关闭套接字
    new_socket.close()


def main():
    """用来完成整体的控制"""
    #1、创建套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #2、绑定
    tcp_server_socket.bind(("", 7890))

    #3、变为监听套接字
    tcp_server_socket.listen(128)

    while True:
        #4、等待新客户端的连接
        new_socket, client_addr = tcp_server_socket.accept()

        #5、为这个客户端服务
        webService(new_socket)

    #关闭监听套接字
    tcp_server_socket.close()
    return None


if __name__ == '__main__':
    main()

python tcp 服务端 多 python写tcp服务器_python tcp 服务端 多_16