python网络编程基础与网络传输

网络编程基础

  1. C/S B/S 架构python

    C:client端,客户端
    B:Browser,浏览器
    S:server,服务端
    C/S 客户端与服务器之间的架构:QQ,微信,游戏,APP等都属于C/S架构
    优势:安全性高,个性化设置,功能全面,响应速度快。
    缺点:开发成本高,维护成本高。(基于APP),面向的客户固定
    B/S:浏览器与服务器之间的架构:它属于C/S架构,最近几年比较流行的特殊的C/S架构
    优势:开发维护成本低,面向用户普遍
    缺点:安全性相对低,响应速度相对慢,个性化的设置单一
  2. 互联网通讯的原理shell

    1. 首先须要经过各类物理链接介质(网线,光纤,无线电波等)将电脑链接起来
    2. 其次要准肯定位到对方计算机(定位到软件)的位置
    3. 经过统一的标准(互联网协议)进行数据的收发
  3. osi 七层协议(tcp/ip五层协议或tcp/ip四层协议)编程

    七层:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层浏览器

    五层:应用层(应,表,会),传输层,网络层,数据链路层,物理层安全

    四层:应用层(应,表,会),传输层,网络层,网络接口层(数,物)服务器

    每层运行常见的物理设备:微信

    传输层:四层交换机,四层的路由器网络

    网络层:路由器,三层交换机架构

    数据链路层:网桥,以太网交换机,网卡socket

    物理层:中继器,集线器,双绞线

    下面咱们来倒着分析一下五层协议

    1. 物理层

      一系列的物理链接介质:网线,光纤,电缆,无线网络等

      发送的数据是0101011100形式的比特数据流,主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0

    2. 数据链路层:遵循以太网协议

      数据链路层的由来:单纯的电信号0和1没有任何意义,必须规定电信号多少位一组,每组表明什么意思

      数据链路层的功能:定义了电信号的分组方式

      以太网协议(ethernet):统一了电信号的分组方式

      Ethernet规定:

      Ethernet规定:一组电信号构成一个数据报,叫作“帧”
      每一数据帧分红:报头 head 和数据 data 两部分
      head 包含:(固定18个字节)
      	发送者/源地址,6个字节
      	接收者/目标地址,6个字节
      	数据类型,6个字节
      data 包含:(最短46个字节,最长1500字节)
      	数据包的具体内容
      head 长度 + data 长度 = 最短64字节,最长1518个字节,超过最大限制就分片发送
      MAC地址:head 中包含的源地址和目标地址的由来,ethernet 规定接入 internet 的设备都必须具有网卡,发送端和接收端的地址即是指网卡地址,即MAC地址
      MAC地址:每块网卡出厂时都被烧制上一个世界惟一的MAC地址,长度为48位2进制,一般由12位16进制数表示(前六位是厂商编号,后六位是流水线号)
      
      广播: 计算机最原始的通讯方式就是吼.
      数据的分组(源地址目标地址) + 广播: 理论上个人计算机就能够通讯了.可是效率过低,每台计算机都须要接收广播的消息,查看是不是给本身的数据.比广播风暴还要严重.
      因此: 广播它是有范围的,在同一子网,局域网内是经过广播的方式,发消息.
    3. 网络层:遵循IP协议

      网络层由来:是为了肯定目标计算机在局域网内的位置

      网络层功能:引入一套新的地址用来区分不一样的广播域/子网,这套地址即网络地址

      IP协议:规定网络地址的协议叫 IP 协议,它定义的地址称之为 ip 地址,普遍采用的v4版本即ipv4,它规定网络地址由32位2进制表示

      一个ip地址一般写为四段十进制数,如:172.16.10.1

      ip地址范围:0.0.0.0 - 255.255.255.255

      ip地址分红两个部分:

      网络部分:标识子网

      主机部分:标识主机

      注意:单纯的ip地址段只是标识了ip地址的种类,从网络部分或主机部分都没法辨识一个ip所处的子网

      例:172.16.10.1与172.16.10.2并不能肯定两者处于同一子网

      子网掩码:

      所谓”子网掩码”,就是表示子网络特征的一个参数。它在形式上等同于IP地址,也是一个32位二进制数字,它的网络部分所有为1,主机部分所有为0。好比,IP地址172.16.10.1,若是已知网络部分是前24位,主机部分是后8位,那么子网络掩码就是11111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。
      知道”子网掩码”,咱们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算(两个数位都为1,运算结果为1,不然为0),而后比较结果是否相同,若是是的话,就代表它们在同一个子网络中,不然就不是。
      好比,已知IP地址172.16.10.1和172.16.10.2的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?二者与子网掩码分别进行AND运算,
      172.16.10.1:10101100.00010000.00001010.000000001
      255255.255.255.0:11111111.11111111.11111111.00000000
      AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0
      172.16.10.2:10101100.00010000.00001010.000000010
      255255.255.255.0:11111111.11111111.11111111.00000000
      AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0
      结果都是172.16.10.0,所以它们在同一个子网络。
      总结一下,IP协议的做用主要有两个,一个是为每一台计算机分配IP地址,另外一个是肯定哪些地址在同一个子网络。

      ip数据包

      ip数据包也分为head和data部分,无须为ip包定义单独的栏位,直接放入以太网包的data部分

      head:长度为20到60字节

      data:最长为65,515字节。

      而以太网数据包的”数据”部分,最长只有1500字节。所以,若是IP数据包超过了1500字节,它就须要分割成几个以太网数据包,分开发送了。

    4. 传输层:遵循端口协议(tcp/udp协议)

      传输层的由来:网络层的IP地址帮咱们区分子网,以太网的MAC帮咱们找到主机, 而后你们使用的都是应用程序,你的电脑上可能同时开启QQ,微信等多个应用程序那么咱们经过ip和Mac找到了目标计算机,如何标识这台主机上的应用程序,答案就是端口,端口即应用程序与网卡关联的编号

      传输层功能:创建端口到端口的通讯

      端口: 0~65535端口号.

      ​ 1~1023系统占用的端口号.

      ​ 1024~8000以内:通常都是有软件占用.

      ​ 自定义端口: 8000 之后

      tcp协议:

      可靠传输,TCP数据包没有长度限制,理论上能够无限长,可是为了保证网络的效率,一般TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包没必要再分割。

      以太网头|ip头|tcp头|数据

      udp协议:

      不可靠传输,”报头”部分一共只有8个字节,总长度不超过65,535字节,正好放进一个IP数据包。

      以太网头|ip头|udp头|数据

      TCP的三次握手四次挥手

      三次握手:

      第一次: 客户端向服务器发送创建联系的syn请求和seq序号

      第二次: 服务器向客户端回复ack确认号和创建联系的syn请求和seq序号

      第三次: 客户端向服务器回复ack确认号

      四次挥手:

      第一次: 客户端向服务器发送断开联系的fin请求和seq序号

      第二次: 服务器向客户端回复ack确认号

      第三次: 服务器向客户端发送断开联系的fin请求和seq序号

      第四次: 客户端向服务器回复ack确认号

      udp与tcp的区别

      一、TCP的优缺点
      (1)TCP的优势:
      TCP的优势是:可靠、稳定。它体如今TCP在传递数据以前,会有三次握手来创建链接;在数据传递时,采用校验和、序列号、确认应答、超时重发、流量控制、拥塞控制,为了提升性能,还采用了滑动窗口、延迟应答和捎带应答等机制;在数据传完后,会断开链接以节约系统资源。
      
      (2)TCP的缺点:
      TCP的缺点:运行速度慢,效率低,占用系统资源多,易被攻击。由于TCP在传递数据以前,要先创建链接,这会消耗时间;在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,并且要在每台设备上维护全部的传输链接,每一个链接都会占用系统的CPU、内存等资源;TCP有确认机制、三次握手机制,这致使TCP容易受到DOS、DDOS、CC等攻击。收到STN洪水攻击,是由于使用 TCP的时候服务器端须要listen,这时须要设置backlog。
      
      二、UDP的优缺点
      (1)UDP的优势:运行速度较快,比TCP安全。
      1)运行速度快,由于 UDP链接没有TCP的三次握手、确认应答、超时重发、流量控制、拥塞控制等机制,并且UDP是一个无状态的传输协议,因此它在传递数据时很是快。
      2)较安全,由于没有TCP的那些机制,UDP较TCP被攻击者利用的漏洞就会少一些。但UDP也是没法避免攻击的,好比:UDP Flood攻击等。
      (2)UDP的缺点:不可靠,不稳定。
      由于UDP没有TCP那些可靠的机制,在数据传递时,若是网络质量很差,就会很容易丢包。
      
      三、TCP和UDP的特色
      (1)TCP的特色
      TCP协议是一种有链接、可靠的、面向字节流、相对比较慢、点对点的传输层协议。TCP协议适用于对可靠性要求比较高的场合。
      (2)UDP的特色
      UDP协议是一种无链接,不可靠、面向数据报、速度比较快、可实现一对一,多对一的传输层协议。UDP协议适用于对实时性有要求的场合。由于UDP不保证可靠性,因此UDP也没有重传机制,也没有拥塞机制,它只是尽最大努力交付数据。

      使用TCP的应用:Web浏览器;文件传输程序。

      使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP),微信qq。

    5. 应用层:遵循应用软件本身定义的协议

      应用层由来: 用户使用的都是应用程序,均工做于应用层,互联网是开放的,你们均可以开发本身的应用程序,数据多种多样,必须规定好数据的组织形式

      应用层功能:规定应用程序的数据格式。

2. 网络传输

  1. socket套接字.

    五层协议: 从传输层包括传输层如下,都是操做系统帮助咱们封装的各类head.你不用去关心.应用层与传输层之间存在一个socket套接字

    # socket的套接字
    '''
    socket 套接字,它存在于传输层与应用层之间的抽象层,
        1. 避免你学习各层的接口,以及协议的使用, socket已经封装好了全部的接口.
            直接使用这些接口或者方法便可,使用起来方便,提高开发效率.
        2. socket就是一个模块.经过使用学习模块提供的功能,
            创建客户端与服务端的通讯,使用方便.
    '''
  2. 单个客户与服务端通讯.

    服务端:

    import socket
    # phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 1. 建立socket对象
    phone = socket.socket() # 能够不写,默认TCP协议下的连接模式
    # 2. 绑定ip地址和端口
    phone.bind(('127.0.0.1', 8848))  # '127.0.0.1'本地回环地址
    # 3. 监听
    phone.listen(5)
    # 4. 接收链接
    conn, addr = phone.accept()  # 程序夯住,等待客户端的数据
    from_client_data = conn.recv(1024)  # 至多接收1024个字节
    print(f'来自客户端{addr}消息{from_client_data.decode("utf-8")}')
    to_client = input('>>>')
    conn.send(to_client.encode('utf-8'))
    
    conn.close()
    phone.close()

    客户端:

    import socket
    # 1. 建立socket对象
    phone = socket.socket() # 能够默认不写
    # 链接服务器ip地址与端口
    phone.connect(('127.0.0.1', 8848))
    # 发消息
    to_server = input('>>>').strip()
    phone.send(to_server.encode('utf-8'))
    # 接收消息
    from_server_data = phone.recv(1024)  # 夯住,等待服务端的数据传过来
    print(f'来自服务端消息:{from_server_data.decode("utf-8")}')
    # 关机
    phone.close()
  3. 通讯循环.

    服务端:

    import socket
    phone = socket.socket() # 能够默认不写
    phone.bind(('127.0.0.1', 8848))  # 本地回环地址
    phone.listen(5)
    conn, addr = phone.accept()  # 程序夯住
    while 1:
        from_client_data = conn.recv(1024)  # 至多接收1024个字节
        print(f'来自客户端{addr}消息{from_client_data.decode("utf-8")}')
        to_client = input('>>>')
        conn.send(to_client.encode('utf-8'))
    conn.close()
    phone.close()
    # 不管你的客户端是否正常关闭,服务端都应该正常关闭,而不是报错.
    # 改进版
    import socket
    phone = socket.socket() # 能够默认不写
    phone.bind(('127.0.0.1', 8888))  # 本地回环地址
    phone.listen(5)
    conn, addr = phone.accept()  # 程序夯住
    while 1:
        try:
            from_client_data = conn.recv(1024)  # 至多接收1024个字节
            if from_client_data == b'q': # 接受到客户端发来的q 退出循环
                break
            print(f'来自客户端{addr}消息{from_client_data.decode("utf-8")}')
            to_client = input('>>>')
            conn.send(to_client.encode('utf-8'))
        except ConnectionResetError:
            break
    conn.close()
    phone.close()

    客户端:

    import socket
    phone = socket.socket() # 能够默认不写
    phone.connect(('127.0.0.1', 8888))
    while 1:
        to_server = input('>>>').strip()
        if to_server.upper() == 'Q':  # 若是用户输入的是Q/q
            phone.send('q'.encode('utf-8'))  # 向服务端发送 q
            break  # 退出循环
        phone.send(to_server.encode('utf-8'))
        from_server_data = phone.recv(1024)  # 夯住,等待服务端的数据传过来
        print(f'来自服务端消息:{from_server_data.decode("utf-8")}')
    phone.close()
  4. 通讯,链接循环.

    服务端:

    import socket
    phone = socket.socket()
    phone.bind(('127.0.0.1', 8888))
    phone.listen(5)
    while 1:
        conn, addr = phone.accept()  # 程序夯住
        while 1:
            try:
                from_client_data = conn.recv(1024)  # 至多接收1024个字节
                if from_client_data == b'q':
                    break
                print(f'来自客户端{addr}消息{from_client_data.decode("utf-8")}')
                to_client = input('>>>')
                conn.send(to_client.encode('utf-8'))
            except ConnectionResetError:
                break
        conn.close()
    phone.close()

    客户端:

    import socket
    phone = socket.socket() # 能够默认不写
    phone.connect(('127.0.0.1', 8888))
    while 1:
        to_server = input('>>>').strip()
        if to_server.upper() == 'Q':
            phone.send('q'.encode('utf-8'))
            break
        phone.send(to_server.encode('utf-8'))
        from_server_data = phone.recv(1024)  # 夯住,等待服务端的数据传过来
        print(f'来自服务端消息:{from_server_data.decode("utf-8")}')
    phone.close()
  5. 利用socket完成获取远端命令的示例.

    服务端

    import socket
    import subprocess
    phone = socket.socket()
    phone.bind(('127.0.0.1', 8888))
    phone.listen(5)
    conn, addr = phone.accept()
    while 1:
        try:
            cmd = conn.recv(1024) #  dir
            obj = subprocess.Popen(cmd.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,)
            result = obj.stdout.read() + obj.stderr.read()
            conn.send(result)
        except ConnectionResetError:
            break
    conn.close()
    phone.close()

    客户端

    import socket
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8888))
    while 1:
        cmd = input('>>>').strip()
        phone.send(cmd.encode('utf-8'))
        result = phone.recv(1024)  # 夯住,等待服务端的数据传过来
        print(result.decode('gbk'))
    phone.close()
相关文章
相关标签/搜索