zoukankan      html  css  js  c++  java
  • python 网络编程

    一、软件开发架构

      c/s架构(client/server)

        c:客户端

        s:服务端

      b/s架构(browser/server)

        b:浏览器

        s:服务器

      ps:bs架构本质也是cs架构

      bs架构未来有很大潜力

    二、网络编程发展史 :任何先进的技术最早都来源于军事

      想实现远程通信第一个需要具备的条件是:

        第一,物理连接介质

        第二,需要有一套公共的标准、协议

      1、OSI协议

        五层:(一般也称七层)

          应用层(应用层,表示层,会话层)

          传输层

          网络层

          数据链路层

          物理连接层

        

        1.物理连接层:基于电信号传输010101010二进制数据

        2.数据链路层(以下两点合成为以太网协议

          1.规定的电信号的分组方式

          2.规定了任何一台接入互联网的计算机都必须有一块网卡(每块网卡都刻有世界上独一无二的编号)

             编号为12位16进制数:前6位是厂商编号,后6位是流水线编号(管这12数叫MAC地址

        基于以太网协议通信

          通信基本靠吼

            广播、单播、广播风暴

        交换机:让连接交换机的计算机实现彼此之间的互联

        局域网:构成互联网的基本单位

            ps:以太网协议不能跨局域网传输

        路由器:连接不同局域网

        网关:网间连接器、协议转换器

        3.网络层

          IP协议

          规定了只要是接入互联网的计算机都必须有一个IP地址

          ip地址特点:点分十进制    且动态分配

          ip地址最小:0.0.0.0   最大:255.255.255.255

          版本:IPV4和IPV6(由于IPV4已经不够表示目前存在的计算机了,所以推出了IPV6)     

        4.传输层

          TCP/UDP都是基于端口工作的协议:

          端口(port):用来唯一标识一台计算机上的某个应用程序

            计算机与计算机之间其实是计算机上的应用程序与应用程序之间的通信

          端口号的范围:0~65535(端口号也是动态分配,关闭再次启动厚,端口号可能变)

            注意:0~1024这些都是操作系统默认使用的端口

            建议:使用8000之后的端口

            Mysql默认端口:3306;Redis默认端口:6379;django默认端口:8000;flask默认端口:5000

        so:ip+port是唯一标识接入互联网一台计算机上的某个应用程序

       5.应用层

        HTTP协议

        FTP协议 

        

        ps:TCP协议(类似打电话):流式协议,可靠协议,三次握手,四次挥手

          UDP协议(类似发短信):数据报协议,无需建立双向通道,数据传输是不安全,将内存中的数据直接发送出去,不会做保留

    三、Socket(套接字)

    TCP:

      发送 send ;接收recv

    1.解决地址绑定套接字问题:

      from socket import SOL_SOCKET,SO_REUSEADDR         

      sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)   #就是它,在bind前加

    import socket
    
    
    server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
    server.bind(('127.0.0.1',8080))  # bind((host,port))  插电话卡  绑定ip和端口
    server.listen(5)  # 开机    半连接池
    
    
    conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞
    data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞
    print(data)
    conn.send(b'hello baby~')  # 给别人回话
    
    
    
    conn.close()  # 挂电话
    server.close()  # 关机
    socket通信服务端

    ps :127.0.0.1 本机回还地址

      只能自己识别自己 其他人无法访问

    import socket
    
    
    client = socket.socket()  # 拿电话
    client.connect(('127.0.0.1',8080))  # 拨号   写的是对方的ip和port
    
    client.send(b'hello world!')  # 对别人说话
    data = client.recv(1024)  # 听别人说话
    print(data)
    
    
    
    client.close()  # 挂电话
    socket通信客户端

    注意点:

      send和recv对应,不要出现两边都相同的情况

        recv是跟内存要数据,至于数据的来源无需考虑

      TCP特点:会将数据量比较小的并且时间间隔比较短的数据一次性打包发送给对方

    UCP:(type=socket.SOCK_DGRAM)

      发送sendto;接收recvfrom;无listen()

    import socket
    
    
    server = socket.socket(type=socket.SOCK_DGRAM)  # UDP协议
    server.bind(('127.0.0.1',8080))
    # UDP不需要设置半连接池 它也没有半连接池的概念
    
    # 因为没有双向通道  不需要accept  直接就是通信循环
    while True:
        data, addr = server.recvfrom(1024)
        print('数据:',data)  # 客户端发来的消息
        print('地址:',addr)  # 客户端的地址
        server.sendto(data.upper(),addr)
    udp服务端
    import socket
    
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    # 不需要建立连接  直接进入通信循环
    server_address = ('127.0.0.1',8080)
    while True:
        client.sendto(b'hello',server_address)
        data, addr = client.recvfrom(1024)
        print('服务端发来的数据',data)
        print('服务端的地址',addr)
    udp客户端

      特点:数据报协议(自带报头)

         没有双向通道,通信类似于发短信

      1.udp协议客户端允许发空

      2.udp协议不会粘包

      3.upd协议服务端不存在的情况下,客户端照样不会报错

      4.udp协议支持并发

    import socket
    
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1',8080))
    
    while True:
        data, addr = server.recvfrom(1024)
        print(data.decode('utf-8'))
        msg = input('>>>:')
        server.sendto(msg.encode('utf-8'),addr)
    简易版QQ服务端
    import socket
    
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    
    while True:
        msg = input('>>>:')
        msg = '来自客户端1的消息:%s'%msg
        client.sendto(msg.encode('utf-8'),server_address)
        data, server_addr = client.recvfrom(1024)
        print(data.decode('utf-8'))
    客户端1
    import socket
    
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    
    while True:
        msg = input('>>>:')
        msg = '来自客户端2的消息:%s'%msg
        client.sendto(msg.encode('utf-8'),server_address)
        data, server_addr = client.recvfrom(1024)
        print(data.decode('utf-8'))
    客户端2

    四、解决黏包问题:(tcp才会有)  

      先了解下struct模块

    import struct
    
    
    # res = 'akdjsladlkjafkldjfgsdafhjksdfhfdgfdsgdfgssgdglkjdfsfdsadkfjlksdjf;klsdkl;fk;lsfdgklj;sfkldgj;kldfg;lfkd;lgk;lsdkfg;lkfd;glskljdklsajkldsa'
    # print('最原始的',len(res))
    
    # 当原始数据特别大的时候 i模式打包不了 需要更换模式?
    # 如果遇到数据量特别大的情况 该如何解决?
    d = {
        'name':'jason',
        'file_size':3455435435345354524534532456546546565466564366463654543453454353455,
        'info':'为大家的骄傲'
    }
    import json
    json_d = json.dumps(d)
    print(len(json_d))
    
    
    res1 = struct.pack('i',len(json_d))
    print(len(res1))
    
    res2 = struct.unpack('i',res1)[0]
    print('解包之后的',res2)
    struct

      服务端

      1.先制作一个发送给客户端的字典

      2.制作字典的报头

      3.发送字典的报头

      4.发送字典

      5.再发真实数据

    import socket
    import subprocess
    import struct
    import json
    
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    
    while True:
        conn, addr = server.accept()
        while True:
            try:
                cmd = conn.recv(1024)
                if len(cmd) == 0:break
                cmd = cmd.decode('utf-8')
                obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                res = obj.stdout.read() + obj.stderr.read()
                d = {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'}
                json_d = json.dumps(d)
                # 1.先制作一个字典的报头
                header = struct.pack('i',len(json_d))
                # 2.发送字典报头
                conn.send(header)
                # 3.发送字典
                conn.send(json_d.encode('utf-8'))
                # 4.再发真实数据
                conn.send(res)
                # conn.send(obj.stdout.read())
                # conn.send(obj.stderr.read())
            except ConnectionResetError:
                break
        conn.close()
    服务端

      客户端

      1.先接受字典的报头

      2.解析拿到字典的数据长度

      3.接受字典

      4.从字典中获取真实数据的长度

      5.接受真实数据

    import socket
    import struct
    import json
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    while True:
        msg = input('>>>:').encode('utf-8')
        if len(msg) == 0:continue
        client.send(msg)
        # 1.先接受字典报头
        header_dict = client.recv(4)
        # 2.解析报头 获取字典的长度
        dict_size = struct.unpack('i',header_dict)[0]  # 解包的时候一定要加上索引0
        # 3.接收字典数据
        dict_bytes = client.recv(dict_size)
        dict_json = json.loads(dict_bytes.decode('utf-8'))
        # 4.从字典中获取信息
        print(dict_json)
        recv_size = 0
        real_data = b''
        while recv_size < dict_json.get('file_size'):  # real_size = 102400
            data = client.recv(1024)
            real_data += data
            recv_size += len(data)
        print(real_data.decode('gbk'))
    客户端

    五、socketserver模块(可实现并发)

    tcp:

    import socketserver
    
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            # print('来啦 老弟')
            while True:
                data = self.request.recv(1024)
                print(self.client_address)  # 客户端地址
                print(data.decode('utf-8'))
                self.request.send(data.upper())
    
    
    if __name__ == '__main__':
        """只要有客户端连接  会自动交给自定义类中的handle方法去处理"""
        server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)  # 创建一个基于TCP的对象
        server.serve_forever()  # 启动该服务对象
    tcp服务端
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    while True:
        client.send(b'hello')
        data = client.recv(1024)
        print(data.decode('utf-8'))
    tcp客户端

    udp:

    import socketserver
    
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            # print('来啦 老弟')
            while True:
                data,sock = self.request
                print(self.client_address)  # 客户端地址
                print(data.decode('utf-8'))
                sock.sendto(data.upper(),self.client_address)
    
    
    if __name__ == '__main__':
        """只要有客户端连接  会自动交给自定义类中的handle方法去处理"""
        server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer)  # 创建一个基于TCP的对象
        server.serve_forever()  # 启动该服务对象
    udp服务端
    import socket
    import time
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    
    while True:
        client.sendto(b'hello',server_address)
        data,addr = client.recvfrom(1024)
        print(data.decode('utf-8'),addr)
        time.sleep(1) # 添加时间,否则udp响应太快,看不到效果
    udp客户端
  • 相关阅读:
    FOC中的Clarke变换和Park变换详解(动图+推导+仿真+附件代码)
    有感FOC算法学习与实现总结
    永磁同步电机 spmsm 和 ipmsm 的区别总结
    Jekyll 解决Jekyll server本地预览文章not found的问题
    STM32 TIM 多通道互补PWM波形输出配置快速入门
    STM32 TIM1高级定时器配置快速入门
    STM32 ADC多通道规则采样和注入采样
    STM32 时钟树配置快速入门
    STM32 TIM 编码器模式采集编码器信号
    STM32 标准库V3.5启动文件startup_stm32f10xxx.s分析
  • 原文地址:https://www.cnblogs.com/xiaowangba9494/p/11311527.html
Copyright © 2011-2022 走看看