ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python网络编程(四)

2022-06-07 18:32:34  阅读:134  来源: 互联网

标签:HTTP 请求 python IP 编程 网络 TCP DNS 服务器


应用层编程

应用层

  • 应用层定义了各种各样的协议规范数据格式,常见的有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

标签:HTTP,请求,python,IP,编程,网络,TCP,DNS,服务器
来源: https://www.cnblogs.com/open-new-world/p/16352892.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有