4.19 python 网络编程和操作系统部分(TCP/UDP/操作系统概念/进程/线程/协程) 学习笔记

1 网络编程概念

1)基本概念

  • 机器的地址

    • mac地址:能够唯一标示你这台机器的
      • arp协议(通过ip找mac):地址解析协议,通过一台机器的ip地址获取到他的mac地址,用到了交换机的 广播和单播
    • ip地址:能够更好的更方便的找到你的机器
  • 局域网

    • 单个局域网内的机器通信
      • 在这里插入图片描述
      • 网段
      • 交换机:只认识mac地址
      • 不能理解ip地址,只能理解mac地址
    • 多个局域网通信
      • 在这里插入图片描述
      • 网关
      • 路由器
      • 可以理解ip地址
  • ip地址

    • 一台机器的临时地址,能够更好更方便的找到你的机器地址

    • ipv4协议:四位点分十进制

      • 0.0.0.0-255.255.255.255
    • ipv6协议

      • 0:0:0:0:0:0 - FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF
    • 公网地址:需要我们自己申请购买的地址

    • 内网地址:保留字段,下面都是内网地址

      • 192.168.0.0-192.168.255.255 学校
      • 172.16.0.0-172.31.255.255 学校
      • 10.0.0.0-10.255.255.255 公司
    • 特殊的ip地址

      • 127.0.0.1 本地回环地址(本机地址,不需要过交换机),测试时候用
    • 查看自己ip地址指令 ipconfig/ifconfig

  • 子网掩码

    • 也是一个ip地址,用来判断两台机器在不在一个局域网内

    • IP : 192.168.12.1
      11000000.00011100.00001111.00000001
      子网掩码:255.255.255.0
      11111111.11111111.11111111.00000000
      进行和运算
      11000000.00011100.00001111.00000000  192.168.12.0
      
  • 端口 port

    • 用来确定一台机器的具体应用
    • 虚拟单位,不是实际存在
    • 0-65535
    • 个人电脑发送请求时操作系统随机分配,服务器端有固定端口
  • osi 7层协议(osi 五层协议是将前三层合并)

    • 协议:
    • 内容(osi五层协议)
      • 应用层(5层)
        • python代码
      • 传输层
        • 预备如何传输,使用的端口port(tcp、udp协议) b’端口+内容’
        • 机器:四层路由器–>四层交换机
      • 网络层
        • 使用的ip(ivp4 ivp6) b’ip+端口+内容’
        • 机器:路由器–>三层交换机
      • 数据链路层
        • 使用的mac地址(arp协议) b’mac地址+ip+端口+内容’
        • 机器:网卡–>二层交换机
      • 物理层(1层)
        • 物理线路
      • 接收时刚好相反
  • tcp 和 udp 协议

    • tcp协议(打电话) - 线下缓存高清电影/qq远程控制/发邮件

      • 先建立连接,才能通信

      • 占用连接/可靠(消息不丢失)/实时性高/慢

      • 建立连接:三次握手

        在这里插入图片描述

      • 连接过程中:收发消息,两次握手

        在这里插入图片描述

      • 断开连接:四次挥手

        在这里插入图片描述

    • udp协议(发短信) - 在线播放视频/qq微信消息

      • 不需要建立连接,就可以通信
      • 不占用连接/不可靠(网络不稳定时会丢失)/实时性底/快

2)应用-最简单的网络通信

  • B/S 架构和 C/S 架构

    • C/S架构(需要安装)
      • client 客户端
      • server 服务端
    • B/S架构
      • browser 浏览器
      • server 服务端
    • C/S 和 B/S 的关系
      • B/S 架构也是 C/S 架构的一种
    • C/S 架构的优点
      • 可以离线使用
      • 功能更完善
      • 安全性更高
    • B/S 架构的优点
      • 不用安装
      • 统一PC端用户的入口
  • socket模块实现简单网络通信测试

    # server.py-->服务器端
    import socket
    
    sk = socket.socket()  # 创建一个server端对象
    
    sk.bind(('127.0.0.1', 9000))  # 给server端绑定一个地址
    sk.listen()  # 开始监听(可以接收)客户端给我的连接了
    
    conn, addr = sk.accept()  # 建立连接
    conn.send(b'hello')
    msg = conn.recv(1024)
    print(msg)
    conn.close()  # 关闭连接
    
    sk.close()
    
# client.py-->客户端
import socket

sk = socket.socket()
sk.connect(('127.0.0.1', 9000))  # 建立连接

msg = sk.recv(1024)  # 接收消息
print(msg)
sk.send(b'byebye')  # 传输消息

sk.close()  # 断开连接
'''
测试时先打开服务器端,再打开客户端进行连接
'''

2 TCP协议和UDP协议进阶(网络编程)

1)TCP协议和UDP协议基于socket模块实现

  • TCP协议

    • 语法:
      • socket(type=socket.SOCK_STRAM) tcp协议的server,默认参数可以不用传
      • bind() 绑定一个ip和端口
      • listen() 监听,代表socket服务的开启
      • accept() 等到有客户端来访问和客户端建立连接
      • send() 直接通过连接发送消息,不需要写地址
      • recv() 只接收消息
      • connect() 客户端/tcp协议的方法,和server端建立连接
      • close() 关闭服务/连接
    • 服务端和多个客户端进行通信
    • 服务器端和客户端进行多次通话
    • 实例代码如下:
    # server.py  服务器端
    import socket
    sk = socket.socket()
    sk.bind(('127.0.0.1',9001))   # 申请操作系统的资源
    sk.listen()
    
    while True:  # 为了和多个客户端进行握手
        conn,addr = sk.accept() # 能够和多个客户端进行握手了
        print('conn : ',conn)
        while True:
            send_msg = input('>>>')
            conn.send(send_msg.encode('utf-8'))
            if send_msg.upper() == 'Q':
                break
            msg = conn.recv(1024).decode('utf-8')
            if msg.upper() == 'Q': break
            print(msg)
        conn.close()    # 挥手 断开连接
    
    sk.close()      # 归还申请的操作系统的资源
    
    # client.py  客户端
    import socket
    sk = socket.socket(type = socket.SOCK_STREAM)  # stream 数据流
    sk.connect(('127.0.0.1',9001))
    
    
    while True:
        msg = sk.recv(1024)
        msg2 = msg.decode('utf-8')
        if msg2.upper() == 'Q':break
        print(msg,msg2)
        send_msg = input('>>>')
        sk.send(send_msg.encode('utf-8'))
        if send_msg.upper() == 'Q':
                break
    sk.close()
    
  • UDP协议

    • 语法:
      • socket.socket(type=socket.SOCK_DGRAM) dgram->datagram 数据包
      • sendto() 需要写一个对方的地址
      • recvfrom() 接收消息和地址
      • close() 关闭服务/连接
    • 服务器端和客户端进行通信
    # server.py  服务器端
    import socket
    
    sk = socket.socket(type = socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',9001))
    while True:
        msg,addr= sk.recvfrom(1024)
        print(msg.decode('utf-8'))
        msg = input('>>>')
        sk.sendto(msg.encode('utf-8'),addr)
    
    # client.py  客户端
    import socket
    
    sk = socket.socket(type=socket.SOCK_DGRAM)
    server = ('127.0.0.1',9001)
    while True:
        msg = input('>>>')
        if msg.upper() == 'Q':break
        sk.sendto(msg.encode('utf-8'),server)
        msg = sk.recv(1024).decode('utf-8')
        if msg.upper() == 'Q':break
        print(msg)
    
    • 识别不同客户端

2)粘包现象

  • 现象:两条或更多条连续发送的消息粘在一起

在这里插入图片描述

  • 粘包发生特点

    • 只出现在tcp协议中,因为tcp协议多条消息之间没有边界,并且还有一大堆优化算法
    • tcp协议多条消息之间没有边界:因为tcp协议和udp协议传输数据时会有最大带宽限制MKT(一般MKT=1500字节),但是tcp协议可以通过Python更改最大带宽限制,从而一次传输大量数据,但是传输数据时没有边界,导致接收后出现粘包现象
  • 原因

    • 发送端发送消息时传输时间间隔很短
    • 接收端没有及时接收消息,而在对方的缓存中堆积在一起造成的
  • 粘包发生的本质:tcp协议是流式传输,数据与数据之间没有边界

  • 解决方法

    • 自定义协议:利用设置边界解决粘包现象

      • 规定最大传输长度为n字节,每次接收时都接受n字节的数据作为一个数据

      • 发送端:

        • 第一种:计算将要发送的数据长度,通过struct模块将长度转换为固定的n字节,发送n个字节的长度
        • 第二种:发送的数据相关的内容组成json:先发json的长度,再发json,json中存了接下来要发送的数据长度,再发数据(文件传输代码中实现了)
      • 接收端:接收n字节,再使用struct.unpack将n字节转换为数字,这个数字就是将要接受的数据的长度,再根据长度接收数据,两条数据就不会粘在一起了

    • struct模块

      • struct.pack(‘i’, 字符串)
      • struct.unpack(‘i’, 字符串)
    • 实例代码

    # server.py  服务器端
    import struct
    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()
    
    conn,addr = sk.accept()
    msg1 = input('>>>').encode()
    msg2 = input('>>>').encode()
    # num = str()  # '10001'
    # ret = num.zfill(4)    # '0006'
    # conn.send(ret.encode('utf-8'))
    blen = struct.pack('i',len(msg1))
    conn.send(blen)
    conn.send(msg1)
    conn.send(msg2)
    conn.close()
    sk.close()
    
    # client.py  客户端
    import time
    import struct
    import socket
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',9001))
    # length = int(sk.recv(4).decode('utf-8'))
    length = sk.recv(4)
    length = struct.unpack('i',length)[0]
    msg1 = sk.recv(length)
    msg2 = sk.recv(1024)
    print(msg1.decode('utf-8'))
    print(msg2.decode('utf-8'))
    
    sk.close()
    

3)文件上传和下载代码

# server端
import socket
import struct
import time

login_state = {
   
    'name' : None,
    'state': False
}

sk = socket.socket()

sk.bind(('127.0.0.1', 9006))
sk.listen()
conn, addr = sk.accept()

msg = conn.recv(1024).decode('utf-8')
with open('register.txt', encoding='utf-8', mode='r') as f:
    for i in f:
        if msg == i.strip():
            conn.send('登陆成功'.encode('utf-8'))
            login_state['name'] = msg.split('|')[0]
            login_state['state'] = True
if login_state['state'] == False:
    conn.send('q'.encode('utf-8'))

while True:
    if login_state['state'] == True:
        conn.send('1上传/2下载:'.encode('utf-8'))
        opt = conn.recv(1024).decode('utf-8')
        if opt == '1':
            dir_test = conn.recv(1024).decode('utf-8').strip().split('/')[-1]
            print(dir_test)
            while True:
                with open('../updateTest/' + dir_test, encoding='utf-8', mode='a') as f:
                    msg = conn.recv(1024).decode('utf-8')
                    if msg.upper() == 'Q':
                        break
                    f.write(msg)
            break

        elif opt == '2':
            file_dir = conn.recv(1024).decode('utf-8')
            with open(file_dir, encoding='utf-8', mode='r') as f:
                for i in f:
                    i = i.strip()
                    print('传输中')
                    # length = struct.pack('i', len(i))
                    # conn.send(length)
                    conn.send(i.encode('utf-8'))
                    time.sleep(1)
            print('传输完成')
            time.sleep(2)
            conn.send('q'.encode('utf-8'))
            break
        else:
            login_state['name'] = None
            login_state['state'] = False
            break
    else:
        break
conn.close()
sk.close()
# client端
import socket
import struct
import time

sk = socket.socket()
sk.connect(('127.0.0.1', 9006))

msg1 = input('name>>>')
msg2 = input('pwd>>>')
msg = msg1.strip
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值