• python网络编程、套接字、HTTP协议


    网络编程 

    网络目的 : 数据的传输

    网络数据传输是一个复杂的过程

    OSI 七层模型 --》 网络通信标准化流程

    • 应用层 : 提供用户服务,具体内容由特定程序规定
    • 表示层 : 数据的压缩优化 
    • 会话层 : 建立应用连接,选择传输层服务
    • 传输层 : 提供不同的传输服务,流量控制
    • 网络层 : 路由选择,网络互连
    • 链路层 : 提供链路交换,具体消息以帧发送
    • 物理层 : 物理硬件,接口,网卡,线路

    osi七层模型优点 : 将功能分开,降低了网络传输中的耦合性,每一部分完成自己的功能。可以在开发和实施的过程中各司其职。实现高内聚和低耦合的功能。

    高内聚 : 单个模块功能尽量单一
    低耦合 : 模块之间尽量减少关联和影响

    四层 

    • 应用层 : 应用层 表示层 会话层
    • 传输层 : 传输层
    • 网络层 : 网络层
    • 物理链路层: 链路层和物理层

    五层(tcp/ip模型)

    • 应用层 : 应用层 表示层 会话层
    • 传输层 : 传输层
    • 网络层 : 网络层
    • 链路层 : 链路层
    • 物理层 : 物理层

     

    协议(网络协议):在网络通信中,各方必须遵守的规定。包括建立什么样的连接,消息结构等

    应用层 : TFTP HTTP DNS SMTP
    传输层 : TCP UDP
    网络层 : IP 
    物理层 : IEEE

     

    网络基本概念

    1、主机: "localhost" 表示本台计算机

      网络上 : 只在本地测试使用
        'localhost' '127.0.0.1'

      如果想在网络上进行测试(自动使用本地可用网卡IP)
        '0.0.0.0' '' '172.60.50.93'

      查看本地 IP 网络信息
        linux上:    ifconfig 
        win上查看本地IP: ipconfig

        ping www.baidu.com  --->14.215.177.38(百度的IP地址)

      获取计算机名称
        socket.gethostname()
        'tedu'

      获取主机IP
        socket.gethostbyname('localhost')
        '127.0.0.1'

    2、IP地址
      在网络上用于区分一台计算 

      IPv4 : 点分十进制 e.g. 192.168.1.72 0-255
        32位二进制表示

      IPv6 : 128

      网络连接测试命令: ping 172.60.50.92

      特殊IP
        127.0.0.1 本地测试IP
        0.0.0.0 本地网卡通用IP
        192.168.1.0 表示当前网段
        192.168.1.1 表示网关
        192.168.1.255 广播地址

      获取服务器主机信息
        socket.gethostbyaddr("www.baidu.com")
        ('127.0.0.1', [], ['119.75.213.61'])
          主机    别名    IP地址

      将ip十进制转化为二进制
        socket.inet_aton("192.168.1.2")
        b'xc0xa8x01x02'

      将ip二进制转化为十进制
        socket.inet_ntoa(b"xc0xa8x01x02")
        '192.168.1.2'

      域名 : 网络服务器IP地址的名称
      url : 在网络上定位某个资源位置

    3、端口号 :端口号是网络地址的一部分,在一个系统中每个网络应用监听不同的端口,以获取对应端口传输的信息

      数字范围 : 1--65535

        1--255 : 一些众所周知的端口
        256--1023 : 系统应用
        1024---65535 : 自用 
        推荐用  >10000 8888 9999 7777 6666

      测试一个软件端口号
        socket.getservbyname('mysql')
        3306
        socket.getservbyname('http')
        80
        socket.getservbyname('ssh')
        22

    传输层服务 

    面向连接的传输服务 ---》 tcp协议 

    传输特征:提供可靠的传输服务
    可靠性表现: 数据在传输过程中,无失序,无差错,无重复,无丢失

    * 传输过程中有建立和断开连接的过程
    三次握手:建立数据传输两端的持续连接
      1. 客户端向服务器发起连接请求(我可以牵你手吗)
      2. 服务器收到连接请求进行确认,返回报文(可以)
      3. 客户端收到服务器确认进行连接创建(牵手成功)

    四次挥手:断开连接的两端,保证数据的传输完整
      1.主动方发送报文,告知被动方要断开连接(我们分手吧,你准备好)
      2.被动方返回报文,告知收到请求,准备断开(知道了)
      3.被动方再次发送报文,告知准备完毕可以断开(你分手吧)
      4.主动方发送报文完成断开(分手了)

    适用情况:文件的上传下载,网络情况良好,需要必须保证可靠性的情况
    比如 : 信息聊天,文件上传下载,邮件,网页获取

    面向无连接的传输服务 ---》 udp协议

     传输特征 :
      * 保证传输的可靠性
      * 无需建立三次握手四次挥手的连接断开过程
      * 消息的收发比较自由,不受其他约束(请原谅我这一生放荡不羁爱自由)

    适用情况 : 网络情况较差,对可靠性要求不高,收发消息的两端不适合建立固定连接
    比如 :网络视频,群聊,发送广播

    套接字----socket

    socket模块的套接字属性

    (s表示一个套接字对象)

    s.type  获取套接字类型  # SocketKind.SOCK_STREAM 流式套接字

    s.family  获取地址族类型  # AddressFamily.AF_INET 获取地址族类型

    s.fileno()  获取套接字的文件描述符(每一个IO操作系统都会为其分配一个不同的正整数,该正整数即为此IO操作系统的文件描述符)

    s.getsockname()  获取套接字绑定的地址  # ('192.168.191.3', 8888)

    s.getpeername()  获取连接套接字另一端的地址 # ('192.168.191.3', 7826)

    s.setsockopt(level,optname,value)  设置套接字选项,丰富修改原有套接字功能

      参数: level 设置选项的类型  optname 每个选项类型中的子选项  value 为选项设置值

    s.getsockopt(level,optname)  获取套接字选项的值

     1 from socket import *
     2 s = socket()
     3 print(s.type)   # SocketKind.SOCK_STREAM 流式套接字
     4 print(s.family) # AddressFamily.AF_INET 获取地址族类型
     5 print(s.fileno())   # 376
     6 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 设置端口可重用
     7 print(s.getsockopt(SOL_SOCKET,SO_REUSEADDR))# 获取选项值 1
     8 s.bind(("192.168.191.3",8888))
     9 print(s.getsockname())  # 获取绑定的地址 ('192.168.191.3', 8888)
    10 s.listen()
    11 c,addr = s.accept() # addr也是链接客户端的地址
    12 print(c.getpeername())  # ('192.168.191.3', 7826)获取链接套接字客户端地址
    13 data = c.recv(1024)
    14 print(data) # b'i'
    15 c.close()
    16 s.close()
    View Code

    socket套接字编程

      套接字:通过编程语言提供的函数接口进行组合,更简单的完成基于tcp和udp通信的网络编程

    套接字的分类

      流式套接字(SOCK_STREAM):传输层基于tcp的协议进行通信

      数据报套接字(SOCK_DGRAM):传输层基于udp的协议进行通信

      底层套接字(SOCK_RAM):访问底层协议的套接字 

    网络收发缓冲区

      1、协调读写速度、减少和磁盘交互

      2、recv和send实际上是从缓冲区获取内容,和向缓冲区发送内容

    recv()特性

      1、如果连接断开,recv会立即结束阻塞返回空字符串

      2、当接收缓存区为空时会阻塞

      3、如果recv一次接收不完缓冲区内容,下次会继续接收,确保数据不丢失

    send()特性

      1、如果另一端不存在还试图使用send进行发送则会产生BrokenPipError异常

      2、当发送缓冲区满时会阻塞

    本地套接字 

    作用:用于本地不同程序间的进行数据传输

    本地套接字的创建流程

    1、创建套接字对象

      sockfd = socket(AF_UNIX,SOCK_STREAM)

    2、绑定本地套接字文件,如果文件不存在,则自动创建文件(绑定套接字文件)

      sockfd.bind(file)

      判断一个文件夹下是否有某个文件  os.path.exists('./tcp_client.py')

      删除一个文件  os.remove(file)  os.remove(file)

    3、监听  listen 

    4、接收发送消息  recv  send

    from socket import * 
    import os 
    
    sock_file =  './sock'    # 使用哪个文件作为套接字文件
    
    if os.path.exists(sock_file):# 判断文件是否已经存在
        os.unlink(sock_file)
    
    sockfd = socket(AF_UNIX,SOCK_STREAM)    # 创建本地套接字
    
    sockfd.bind(sock_file)    # 绑定
    sockfd.listen(5)    # 监听
    
    while True:
        c,addr = sockfd.accept()     # 建立连接
        while True:
            data = c.recv(1024)
            if not data:
                break
            print(data.decode())
        c.close()
    sockfd.close()
    服务端
    from socket import * 
    
    sock_file = "./sock"    # 确保通信两端用相同的套接字文件
    
    sockfd = socket(AF_UNIX,SOCK_STREAM)    # 创建套接字
    
    sockfd.connect(sock_file)    # 链接
    
    while True:
        msg = input("Msg>>")
        if msg:
            sockfd.send(msg.encode())
        else:
            break 
    
    sockfd.close()
    客户端

    TCP粘包

      产生原因:TCP传输采用字节流的方式,消息之间没有边界,如果发送的速度比接收速度快,会造成多次发送的内容被一次接收,形成意义上的误解即粘包

      产生条件:当使用send快速的连续发送极有可能产生粘包

      影响:如果每次发送的内容代表一个独立的意思,需要单独识别,就会产生粘包。但是如果多次发送的内容就是一个连续的整体,此时就不需要处理。

      如何处理

        1、每次发送后加一个结尾标志,接收端通过标志进行判断

        2、发送一个数据结构

        3、每次发送中间有一个短暂的延迟(有一个间隔)

    TCP接收多个客户端连接,且可以持续发送消息

    from socket import * 
    
    sockfd = socket(AF_INET,SOCK_STREAM)    #创建套接字
    
    sockfd.bind(('127.0.0.1',9999))    #绑定地址
    
    sockfd.listen(5)    #设置监听
    
    while True:    # 等待客户端连接
        print("Waiting for connect...")
        connfd,addr = sockfd.accept()
        print("Connect from",addr)
        while True:    # 消息收发
            data = connfd.recv(1024)
            if not data:
                break
            print("Receive:",data.decode())
            n = connfd.send(b"Receive your message")
            print("send %d bytes"%n)
        
        connfd.close()    # 关闭套接字
    
    sockfd.close()
    TCP-server
    from socket import * 
    
    sockfd = socket()    #创建套接字
    
    sockfd.connect(('127.0.0.1',9999))    #发起连接
    
    while True:    #消息收发
        
        msg = input("Msg>>")
        if not msg:
            break
        sockfd.sendall(msg.encode())
        data = sockfd.recv(1024)
        print(data.decode())
    
    sockfd.close()
    TCP-client

    HTTP

    http协议-->超文本传输协议  应用层协议,HTTP是基于TCP协议编码的。

    用途:网页的获取,基于网站的数据传输,基于http协议的数据传输

    特点

    • 应用层协议。传输层使用TCP传输
    • 无状态协议,不记录用户的通信内容
    • http1.1---->http2.0 成熟稳定

    工作模式:

      使用http双方均遵守http协议规定发送接收消息体

      请求方,根据协议组织请求内容给对象

      服务方,收到内容按照协议解析

      服务方,将回复内容按照协议组织发送给请求方

      请求方,收到回复根据协议解析

    HTTP请求格式

    格式: 请求行 请求头 空行 请求体

    1、请求行(熟悉格式及作用): 提供具体的请求类别, 请求内容

        GET  /  index.html / HTTP/1.1

        请求类别  请求内容    协议版本

        请求种类 :   GET 获取网络资源
              POST 提交一定的附加数据,得到返回 结果
              HEAD 获取响应头
              PUT 更新服务器资源
              DELETE 删除服务器资源
              CONNECT 预留
              TRACE 测试
              OPTIONS 获取服务器性能

    2、请求头 : 对请求内容的具体描述, 键值对的形式对请求信息进行描述

      e.g.

        Accept: text/html
        Accept-Encoding: gzip, deflate, br
        Accept-Language: zh-CN,zh;q=0.9
        Cache-Control: max-age=0
        Connection: keep-alive

    3、空行

    4、请求体 : 具体的请求参数

      (GET参数,或者POST提交的内容)

    HTTP响应格式

    1、响应行 反馈具体的响应情况

      HTTP/1.1   200   OK
      版本信息  响应码  附加信息

      响应码 :

    • 1xx 提示信息 表示请求已经接受
    • 2xx 响应成功
    • 3xx 响应需要重新请定向
    • 4xx 客户端错误
    • 5xx 服务器错误

      常见响应码 :

    • 200 成功
    • 404 请求页面不存在
    • 401 没有访问权限
    • 500 服务器发生未知错误
    • 503 服务器暂时无法执行

    2、响应头 对响应信息的具体描述

      e.g.
      Cache-Control: private
      Connection: Keep-Alive

    3、空行
    4、响应体:将客户想要的内容进行返回

    搭建HTTP本地服务器 

    做的是一个本地服务端,接收来自浏览器客户端的请求

    # 返回第一行   GET / HTTP/1.1
    1. 接收http请求; 解析http请求
    2. 响应一个网页给客户端
    from socket import *
    
    # 处理客户端请求
    def handle(connfd):
      request = connfd.recv(4096)   # 接收请求
    
      # 防止客户端断开request为空
      if not request:
        return
      request_line = request.splitlines()[0]    # 返回第一行   GET / HTTP/1.1
      info = request_line.decode().split(' ')[1]
      if info == '/':
        with open('index.html') as f:
          response = "HTTP/1.1 200 OK
    "            # 响应行
          response += "Content-Type:text/html
    "    # 响应头
          response += '
    '                          # 空行
          response += f.read()                        # 响应体
      else:
        response = "HTTP/1.1 404 Not Found
    "
        response += "Content-Type:text/html
    "
        response += '
    '
        response += "<h1>Sorry...</h1>"
    
      connfd.send(response.encode())    # 发送给浏览器
    
    sockfd = socket()   # 搭建tcp网络
    sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    sockfd.bind(('0.0.0.0',8000))       # 绑定地址
    sockfd.listen(3)                    # 设置监听
    while True:
      connfd,addr = sockfd.accept()     # 获取连接端和地址
      handle(connfd)      # 处理客户端请求

     在浏览器输入地址:127.0.0.1:8888,即可得到网页显示!

  • 相关阅读:
    Linux目录树与磁盘分区
    私有服务器外网访问zerotier解决方案
    ubuntu防火墙相关
    “ssh协议”简单使用
    Ubuntu软件安装小记
    怎么说服领导,能让我用DDD架构肝项目?
    金3银4面试前,把自己弄成卷王!
    开发 IDEA Plugin 引入探针,基于字节码插桩获取执行SQL
    《重学Java设计模式》作者开始录视频了!
    《Mybatis 手撸专栏》第1章:开篇介绍,我要带你撸 Mybatis 啦!
  • 原文地址:https://www.cnblogs.com/LXP-Never/p/9432210.html
Copyright © 2020-2023  润新知