python网络编程(四)

2022/6/8 1:21:24

本文主要是介绍python网络编程(四),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

应用层编程

应用层

  • 应用层定义了各种各样的协议规范数据格式,常见的有HTTP、FTP、SMTP等,HTTP是一种比较常用应用层协议

  • HTTP

    HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议,它是基于TCP的应用层协议客户端服务端进行通信的规则,它的模式非常简单,就是客户端发起请求,服务端相应请求

    • 请求行:包含请求方法、请求地址和HTTP协议版本。

    • 消息报头:包含了一系列的键值对。

    • 请求正文(可选):注意和消息报头之间有一个空行。

      服务端相应响应

    • 状态行:包含HTTP协议版本、状态码和状态描述,以空格分隔。

    • 相应头:消息报头,包含一系列的键值对。

    • 响应正文:返回内容,注意和响应之间有一个空行。

  • 请求方法

    • GET:从服务器获取指定(请求地址)的资源的信息,它通常只用于读取数据,就像数据库查询一样,不会对资源进行修改。
    • POST:想指定资源提交数据(比如提交表单,上传文件),请求服务器进行处理。数据被包含在请求正文中,这个请求可能会创建新的资源或更新现有的资源。
    • PUT:通过指定资源的唯一表识(在服务器上的具体存放位置),请求服务器创建或更新资源。
    • DELETE:请求服务器删除指定资源。
    • HEAD:与GET方法类似,从服务器获取资源信息,和GET方法不同的是,HEAD不含有呈现数据,仅仅是HTTP头信息。HEAD的好处在于,只用这个方法可以在不必传输全部的内容情况下,就可以获取资源的元信息(或元数据)。
    • OPTIONS:该方法可使服务器传回资源所支持的所有HTTP请求方法。
  • 状态码

    • 1XX消息:请求已被服务接收,继续处理。
    • 2XX成功:请求已成功被服务器接收、理解、并接受
      • 200:OK
      • 201:Created 已创建
      • 202:Accepted 接收
      • 203:Non- Authoritative Information 非认证消息
      • 204:No Content 无内容
    • 3XX重定向:需要后续操作才能完成这一请求
      • 301:Moved Permanently 请求永久重定向
      • 302:Moved Temporarily 请求临时重定向
      • 304:Not Modified 文件为修改,可以直接使用缓存的文件
      • 305:Use Proxy 使用代理
    • 4XX请求错误:请求含有词法错误或者无法被执行
      • 400:Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
      • 401:Unauthorized 请求未经授权。这个状态代码必须和WWW- Authenticate报头域一起使用。
      • 403:Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因。
      • 404:Not Found 请求的资源不存在,例如,输入错了URL或者服务端没有启动。
    • 5XX服务器错误:服务器在处理某个正确请求是发生错误
      • 500:Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
      • 503:Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。
      • 504:Gateway Time-out 网关超时。

Python 实现文本服务器

  • server.py

    import socket
    import threading
    
    
    def handle_client(client: socket.socket, address):
        # 接收客户端的请求
        request_data = client.recv(1024)
        # 打印数据
        print(f"客户端的地址为:{address},请求的数据为:{request_data.decode()}")
        # 向客户端相应数据,相应的格式是要遵循HTTP协议规范
        # 状态行:包含HTTP协议的版本、状态码和状态描述符,以空格相隔
        response_status = "HTTP/1.1 200 OK\r\n"
        # 自定义响应头
        response_header = "Server:New Server\r\n"
        # 相应体
        response_body = "Hello World"
        # 组装响应数据
        response = response_status + response_header + '\r\n' + response_body
        # 将数据回复给客户端
        client.send(response.encode())
        # 关闭client
        client.close()
    
    
    def main():
        # 创建一个TCP的HTTP服务器
        with socket.socket(type=socket.SOCK_STREAM) as server:
            # 如果地址什么都不写,代表着绑定着是我当前机器的所有IP地址
            server.bind(("", 8080))
            # 服务器监听
            server.listen(128)
            # 打印启动信息
            print("服务器已经启动!")
            # 不停的接收客户端的请求
            while True:
                # 接收客户端的请求,返回客户端的socket和address
                client, address = server.accept()
                # 采用多线程处理多个客户端的请求
                thread = threading.Thread(target=handle_client, args=(client, address))
                # 启动线程
                thread.start()
    
    
    if __name__ == '__main__':
        main()
    
  • 运行后在网页输入127.0.0.1:8080

    后台打印出请求行和消息报头

    通过F12可以查看请求和响应信息,与后台输出一致

Python 实现Html服务器

  • server.py

    import socket
    import threading
    import os
    
    
    # 存放html的路径,我放在D盘下的
    HTML_PATH = "D:\\"
    
    
    def handle_client(client: socket.socket, address):
        # 接收客户端的请求
        request_data = client.recv(1024)
        # 打印数据
        print(f"客户端的地址为:{address},请求的数据为:{request_data.decode()}")
        # 通过空格分隔客户端请求数据
        # 请求行:GET / HTTP/1.1 ==> 请求方法、请求地址和HTTP协议版本
        request = request_data.decode().split(" ")
        # 拿到客户端请求的文件,也就是请求地址。例如:index.html
        if request[1] == '/':
            filename = '/index.html'
        else:
            filename = request[1]]
        # 向客户端相应数据,相应的格式是要遵循HTTP协议规范
        # 状态行:包含HTTP协议的版本、状态码和状态描述符,以空格相隔
        response_status = "HTTP/1.1 200 OK\r\n"
        # 自定义响应头
        response_header = "Server:New Server\r\n"
        # 有可能客户端请求的是图片或者视频文件,所以需要用rb的形式读取
        try:
            with open(os.path.join(HTML_PATH, filename), 'rb') as f:
                # 响应体
                response_body = f.read().decode()
        except Exception as e:
            _ = e
            response_status = "HTTP/1.1 404 Not Found\r\n"
            response_body = "File Not Found"
        # 组装响应数据
        response = response_status + response_header + '\r\n' + response_body
        # 将数据回复给客户端
        client.send(response.encode())
        # 关闭client
        client.close()
    
    
    def main():
        # 创建一个TCP的HTTP服务器
        with socket.socket(type=socket.SOCK_STREAM) as server:
            # 如果地址什么都不写,代表着绑定着是我当前机器的所有IP地址
            server.bind(("", 8080)))
            # 服务器监听
            server.listen(128)
            # 打印启动信息
            print("服务器已经启动!")
            # 不停的接收客户端的请求
            while True:
                # 接收客户端的请求,返回客户端的socket和address
                client, address = server.accept()
                # 采用多线程处理多个客户端的请求
                thread = threading.Thread(target=handle_client, args=(client, address))
                # 启动线程
                thread.start()
    
    
    if __name__ == '__main__':
        main()
    
  • index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>My Web Server</title>
    </head>
    <body>
    <h1>Hello World</h1>
    </body>
    </html>
    
  • 运行server.py,浏览器输入http://127.0.0.1:8080

    后台的数据为:

  • 浏览器输入http://127.0.0.1:8080/index.html

    后台的数据为:

  • 浏览器输入http://127.0.0.1:8080/index1.html

    后台数据为:

HTTP数据流传输过程

宏观层面

  1. 当网页上输入域名之后,会先去本机上的Host文件当中获取对应的IP地址,如果能取到,则使用Host文件的解析结果。

    • 格式:IP地址 + 空格 + 域名

    • Windows: C:\Windows\system32\drivers\etc\hosts

    • Mac: /private/etc/hosts

    • Linux: /etc/hosts

  2. 如果Host文件中没有该域名的解析结果,那么就会去使用DNS协议来获取IP。在DNS协议中,PC会向你的本地DNS服务器获取对应的IP地址信息。本地DNS服务器的IP路由分为两种:通过手动设置的静态IP地址,通过动态DHCP协议获取动态IP地址

  3. 接下来建立TCP连接。在TCP协议中,建立TCP需要与目的服务器三次握手,三次握手的流程为:

    • 我向目的服务器发送消息(SYN)
    • 服务器应答并给我发送消息(SYN、ACK)
    • 我应答(ACK)
  4. 三次握手成功后,开始使用HTTP协议请求网页内容。发送HTTP请求报文,服务器给出应答。

  5. 如果服务器禁止访问就会回复“Forbidden”或者“file not found”等,如果服务器正常则会回复“OK”,以及200的状态码,并传回相应的数据,若传回的数据是HTML形式的文本,浏览器就会将数据渲染到屏幕上。

微观层面

  1. 域名解析
    1. 浏览器向本机DNS模块发出DNS请求,DNS模块生成相关的DNS报文;
    2. DNS模块将生成的DNS报文传递给传输层的UDP协议单元;
    3. UDP协议单元将该数据封装成UDP数据报,传递给网络层的IP协议单元;
    4. IP协议单元将该数据封装成IP数据包,其目的IP地址为DNS服务器的IP地址;
    5. 封装好的IP数据包将传递给数据链路层的协议单元进行发送;
    6. 发送时在ARP缓存中查询相关数据,如果没有,就发送ARP广播(包含代查询的IP地址,收到广播的主机检查自己的IP,符合条件的主机将含有自己MAC地址的ARP包发送给ARP广播的主机)请求,等待ARP回应;
    7. 得到ARP回应后,将IP地址(目的IP地址)与路由的下一跳MAC地址(DNS的MAC地址)对应的信息写入ARP缓存表;
    8. 写入缓存表后,以路由下一跳的地址(DNS的MAC地址)填充目的地址,以数据帧形式转发;
    9. 转发可能会经过多次;
    10. DNS请求到达DNS服务器数据链路层协议单元;
    11. DNS服务器的数据链路层协议单元解析数据帧,将内部的IP数据包传递给网络层IP协议单元;
    12. DNS服务器的IP协议单元解析IP数据包,将内部的UDP数据报传递给传输层协议单元;
    13. DNS服务器的UDP协议单元解析收到的UDP数据报,将内部的DNS报文传递给DNS服务单元;
    14. DNS服务单元将域名解析成对应的IP地址,产生DNS回应报文;
    15. DNS回应报文->UDP->IP->MAC->我的主机;
    16. 我的主机收到数据帧,将数据帧->IP->UDP->浏览器;
    17. 将域名解析结果以域名和IP地址对应的形式写入DNS缓存表;
  2. TCP三次握手
    1. 向目的主机发送TCP连接8请求报文;
    2. 该TCP报文中SYN标志位设为1,表示连接请求;
    3. 该TCP报文通过IP(DNS)->MAC(ARP)->网关->目的主机;
    4. 目的主机收到数据帧,通过IP->TCP,TCP协议单元回应请求应答报文;
    5. 该报文中SYNACK标志设为1,表示连接请求应答;
    6. 该TCP报文通过IP(DNS)->MAC(ARP)->网关->我的主机;
    7. 我的主机收到数据帧,通过IP->TCP,TCP协议单元回应请求确认报文(ACK
    8. 该TCP报文通过IP(DNS)->MAC(ARP)->网关->目的主机‘
    9. 目的主机收到数据帧,通过IP->TCP,连接建立完成;
  3. HTTP传输数据
    1. 浏览器域名发出请求;
    2. 该请求报文通过HTTP->TCP->IP(DNS)->MAC(ARP)->网关->目的主机;
    3. 目的主机收到数据帧,通过IP->TCP->HTTP,HTTP协议单元会回应HTTP协议格式封装好的HTML形式数据;
    4. 该HTML数据通过TCP->IP(DNS)->MAC(ARP)->网关->我的主机;
    5. 我的主机收到数据帧,通过IP->TCP->HTTP->浏览器,浏览器以网页的形式显示HTML内容;
  4. TCP四次挥手
    1. 浏览器向目的主机发出TCP连接结束请求报文,此时进入FIN WAIT状态;
    2. 该报文FIN标志位设为1,表示结束请求;
    3. TCP结束请求报文通过IP(DNS)->MAC(ARP)->网关->目的主机;
    4. 目的主机收到数据帧,通过IP->TCP,TCP协议单元回应结束应答报文(ACK);
    5. 当前只是进行回应,因为目的主机可能还有数据要传,并不着急断开连接;
    6. 该报文中ACK标志位设为1,表示收到结束请求;
    7. 目的数据发送完所有数据后,向我的主机发出TCP连接结束请求报文;
    8. 该报文FIN标志位设为1,表示结束请求;
    9. TCP结束请求报文通过IP(DNS)->MAC(ARP)->网关->我的主机;
    10. 我的主机收到数据帧,通过IP->TCP,TCP协议单元回应应答报文,此时进入TIME WAIT状态,因为不相信网络时可靠的,如果目的主机没收到还可以重发
    11. 该报文中的FIN标志位均设为1,表示结束应答;
    12. 该TCP回应报文通过IP(DNS)->MAC(ARP)->网关->目的主机;
    13. 目的主机关闭连接;
    14. TIME WAIT等待结束后,没有收到回复,说明目的正常关闭了,我的主机也关闭连接;

应用层协议

DHCP动态主机分配协议

  • DHCP主机动态配置协议,是一个局域网的网络协议,使用UDP协议工作,常用的2个端口:67(DHCP service),68(DHCP client)

    DHCP通常被用于局域网环境,主要作用是集中的管理分配IP地址,使client动态的获得IP地址Gateway地址DNS服务器地址等信息,并能够提升地址的使用率。

  • DHCP工作流程

    image-20220422100236379



这篇关于python网络编程(四)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程