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

网络编程基础

  1. C/S B/S 架构

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

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

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

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

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

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

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

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

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

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

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

    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的区别

      1、TCP的优缺点
      (1)TCP的优点:
      TCP的优点是:可靠、稳定。它体现在TCP在传递数据之前,会有三次握手来建立连接;在数据传递时,采用校验和、序列号、确认应答、超时重发、流量控制、拥塞控制,为了提高性能,还采用了滑动窗口、延迟应答和捎带应答等机制;在数据传完后,会断开连接以节约系统资源。
      
      (2)TCP的缺点:
      TCP的缺点:运行速度慢,效率低,占用系统资源多,易被攻击。因为TCP在传递数据之前,要先建立连接,这会消耗时间;在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,每个连接都会占用系统的CPU、内存等资源;TCP有确认机制、三次握手机制,这导致TCP容易受到DOS、DDOS、CC等攻击。收到STN洪水攻击,是因为使用 TCP的时候服务器端需要listen,这时需要设置backlog。
      
      2、UDP的优缺点
      (1)UDP的优点:运行速度较快,比TCP安全。
      1)运行速度快,因为 UDP连接没有TCP的三次握手、确认应答、超时重发、流量控制、拥塞控制等机制,而且UDP是一个无状态的传输协议,所以它在传递数据时非常快。
      2)较安全,因为没有TCP的那些机制,UDP较TCP被攻击者利用的漏洞就会少一些。但UDP也是无法避免攻击的,比如:UDP Flood攻击等。
      (2)UDP的缺点:不可靠,不稳定。
      因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。
      
      3、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()

转载于:https://www.cnblogs.com/changyifei-8/p/11202167.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值