网络编程(三)

网络编程(三)


上周回顾


socket

简介:socket套接字专门用于远程数据的交互

模块:使用socket的整合功能就相当于编写了OSI七层协议

基本使用(基于TCP):

import socket  # 服务端

server = socket.socket()  # 启用,括号内不填入参数默认使用TCP协议
server.bind(('127.0.0.1', 8888))  # 服务器地址,默认填入本机地址和8000之后的端口号
server.listen(2)  # 等待链接,设置半连接池
sock, addr = server.accept()  # 用变量名接收客户端发送的消息和客户端端口号

while True:
    data = sock.recv(1024)  # 使用.recv(字节数大小) 来接收具体的消息
    if len(data) == 0:  # 客户端断开链接的判断
        print('客户端已经退出链接')
        server.close()  # 关机
        break
    else:
        print(data.decode('utf8'))  # 接收客户端发送的消息
    word = input('请输入您需要回复的消息').strip()
    sock.send(word.encode('utf8'))


import socket  # 客户端


client = socket.socket()  # 产生一个对象
client.connect(('127.0.0.1', 8888))  # 连入服务端地址与端口号

while True:
    word = input('请输入您发送的消息').strip()  
    if len(word) == 0:
        print('发送的消息不能为空')
        continue
    client.send(word.encode('utf8'))
    data = client.recv(1024)
    print(data.decode('utf8'))

黏包

struct模块里有两个方法:

pack :把任意长度数字转化成具有固定4个字节长度的字节流

unpack :把4个字节值恢复成原来的数字,返回最终的是元组


今日内容详解


作业

服务端代码

import socket
import struct
import os
import sys
import json
sys.path.append(os.path.dirname(__file__))

server = socket.socket()  # 启用,括号内不填入参数默认使用TCP协议
server.bind(('127.0.0.1', 8888))  # 服务器地址,默认填入本机地址和8000之后的端口号
server.listen(2)  # 等待链接,设置半连接池
sock, addr = server.accept()  # 用变量名接收客户端发送的消息和客户端端口号

data_dict = {
    'file_name': 'a.mp3',
    'file_size': os.path.getsize('视频地址') 
}
# 编写一个字典,放入视频相关的消息和实际大小
data_dict_str = json.dumps(data_dict)  # 转换成json字符串格式
data_dict_str_bytes = data_dict_str.encode('utf8')  # 转换成二进制
data_dict_str_bytes_len = struct.pack('i',len(data_dict_str_bytes))  # 打包成4
sock.send(data_dict_str_bytes_len)  # 发送4,实际为字典大小
sock.send(data_dict_str_bytes)  # 发送字典
with open('a.txt','rb') as f:
    for i in f:
        sock.send(i)  # 发送视频数据
        
客户端代码
        
import socket
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1', 8888))

data_dict_str_bytes_len = client.recv(4)  # 接受字典大小
data_dict_len = struct.unpack('i', data_dict_str_bytes_len)[0]  # 解压出实际大小的字典
data_dict_bytes = client.recv(data_dict_len)  # 根据实际字典大小去接受实际字典
data_dict = json.loads(data_dict_bytes)  # 读取字典的数据,其中包涵视频文件实际大小
real_size = 0
with open('b.txt', 'wb') as f:
    while real_size < data_dict.get('file_size'): # 根据视频实际大小循环写入
        writer_txt = client.recv(1024)
        real_size += len(writer_txt)
        f.write(writer_txt)
 

UDP协议

import socket  # 服务端
server = socket.socket(type=socket.SOCK_DGRAM)  # 自己指定UDP协议(默认是TCP协议)
server.bind(('127.0.0.1', 8080))  # 和TCP几乎一样,写入地址和端口号
msg, addr = server.recvfrom(1024)  # 待接收
print('msg>>>:', msg.decode('utf8'))  # 额外打印出端口号,为了确定是哪个客户端
print('addr>>>:', addr)  # 额外打印出端口号,为了确定是哪个客户端
server.sendto(b'hello baby', addr)


import socket  # 客户端
client = socket.socket(type=socket.SOCK_DGRAM)  # 自己指定UDP协议(默认是TCP协议)
server_addr = ('127.0.0.1', 8080)  # 查找通讯录
client.sendto(b'hello server baby', server_addr)
msg, addr = client.recvfrom(1024)
print('msg>>>:', msg.decode('utf8'))
print('addr>>>:', addr)

操作系统的发展史


我们可以用一句话表达操作系统的发展史:操作系统的发展史其实就是提升CPU利用率的过程

第几代计算机 特点 工作过程 优点 缺点
第一代 无操作系统 一个人独享计算机,一开始使用插件版,后面使用穿孔卡片 程序员独享计算机,可以随时更改 同一时间只能执行一个操作,cpu利用率极低
第二代 批处理系统 一次只把一个程序读取到内存,执行完毕后,再执行下一个程序,称为串行。 充分利用了计算机资源 整个过程是需要人参与的,程序员效率低,程序串行运行
第三代 脱机批处理系统 并发:多个任务看起来是同时运行的 充分利用了计算机资源并且不需要人参与,计算机可以根据任务需求分配完成 我不知道

串行

一次只把一个程序读取到内存,执行完毕后,再执行下一个程序,称为串行


并发

1、空间上的复用:多道程序在运行前先必须加载到内存中

2、时间上的复用:多个任务复用cpu的时间片,通俗地讲就是cpu在多个程序之间来回切换
什么时候切换呢?

I:当一个任务遇到IO,肯定要切换-》提升效率

II:一个任务没有遇到IO但是占用CPU时间过长,也要切换=》降低效率


假设三项任务,分别是1分钟,2分钟,3分钟

如果是串行,需要1+2+3=6分钟

如果是并发,只需要3分钟


并发与并行

并发是因为执行任务的方式符合并发这个概念

就好比一个人做多件事情,人在这个多件事情中来回穿插完成各项事情

将这个人替换成CPU就可以表示为让CPU在多个程序之间利用多道技术来回切换+保存状态


并行:必须在同一时间同时运行多个任务

单个人肯定完成不了,单个CPU肯定也完成不了


高并发与高并行

​ 可以完成大量下达的任务叫做高并发

​ 现实可能存在大量人力同事完成大量的任务,但在计算机中不存在,一般8核很高了


进程理论

程序:未被运行的代码集合

进程:正在运行的代码集合

进程调度算法发展史

  1. 先来先服务
    对短作业任务不太友好

  2. 短作业优先
    多长作业任务不太友好
    3. 时间片轮转法与多级反馈队列
    时间片轮转法:先公平的将CPU分给每个人执行
    多级反馈队列:根据作业长短的不同再合理分配CPU执行时间


同步与异步

同步:提交任务之等待结果,得到下一步指令后才会执行其他的任务

异步:提交完任务之后暂时不管结果,继续执行其他任务

异步的效率肯定是由于同步


阻塞与非阻塞

进程三状态转换图

​ 就绪态:程序之进入运行态之前肯定要处于就绪态

​ 运行态:程序被CPU执行着

​ 阻塞态:程序执行过程中有IO操作

​ 非阻塞:就绪态、运行态


同步阻塞:专心完成一个任务,每个任务完成后才能继续做下一个任务

同步非阻塞:在完成当前任务的途中,可以处于就绪态,但当前任务完全前依旧不能做下一个任务

异步阻塞:专心完成一个任务,期间不能做别的事情,提交完任务就可以直接做下一项任务

异步非阻塞:在完成当前任务的途中,可以处于就绪态,提交完任务就可以直接做下一项任务


今日小结

找回状态,认真学习!

posted @ 2022-04-18 21:03  Eason辰  阅读(39)  评论(0)    收藏  举报