tcp\udp 操作系统发展史

为什么会出现粘包现象

TCP
        三次握手
        可靠协议,流式协议
    
    粘包问题的产生:
        1.接收方:
            我不知道我要接受的数据的总长度
        2.发送方:
            由于TCP协议的内部优化算法negle
            1.会将数据量比较的小的并且时间间隔比较短的数据一次性打包发送
"""
首先只有在TCP协议中才会出现粘包现象,因为TCP协议是流式协议
它的特点是将数据量小并且时间间隔比较短的数据一次性打包发送出去
本质其实还是因为我们不知道需要接收的数据的长短
"""
# 如何解决粘包问题?
# 1 发送数据直接先告诉对方数据量的大小
# 2 利用struct模块定制我们自己的消息传输协议

socket发送大文件示例

# 客户端
import struct
import json
import socket
import os

client = socket.socket()
client.connect(('127.0.0.1', 8080))

file_size = os.path.getsize(r'/Users/jiboyuan/PycharmProjects/aboutsocket/10 解决粘包问题终极版.mp4')
file_path = r'/Users/jiboyuan/PycharmProjects/aboutsocket/10 解决粘包问题终极版.mp4'
data_dic = {
    'file_name': '澳门最大线上赌场开业啦.mp4',
    'file_size': file_size
}
header_json = json.dumps(data_dic)
header_bytes = header_json.encode('utf-8')
# 制作字典的报头
header = struct.pack('i', len(header_bytes))
# 发送报头
client.send(header)
# 发字典数据
client.send(header_bytes)
# 打开文件发送文件数据
with open(file_path,'rb') as f:
    for line in f:
        client.send(line)

# 服务端
import socket
import json
import struct

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

while True:
    conn, addr = server.accept()
    while True:
        try:
            header = conn.recv(4)
            if len(header) == 0:break
            dic_len = struct.unpack('i', header)[0]

            real_dic = json.loads(conn.recv(dic_len).decode('utf-8'))
            print(real_dic)
            file_name = real_dic.get('file_name')
            file_size = real_dic.get('file_size')
            recv_size = 0
            with open(file_name, 'wb') as f:
                while recv_size < file_size:
                    recv_data = conn.recv(1024)
                    f.write(recv_data)
                    recv_size += len(recv_data)
        except ConnectionResetError:
            break

UDP协议

UDP
    数据报协议
    没有双向通道
    
    1.UDP协议不存在粘包问题
    2.客户端可以发空
    3.udp可以实现并发的效果
    4.服务端不存在,也不影响客户端朝服务端发送数据
"""
1.udp协议客户端允许发空
2.udp协议不会粘包
3.udp协议服务端不存在的情况下,客户端照样不会报错
4.udp协议支持并发

UDP叫数据报协议,意味着发消息都带有数据报头
udp的server不需要就行监听也不需要建立连接
在启动服务之后只能被动的等待客户端发送消息过来,客户端发送消息的时候,要带上服务端的地址
服务端在回复消息的时候,也需要带上客户端的地址
"""
# 服务端
import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

msg, addr = server.recvfrom(1024)
print(msg.decode('utf-8'))
server.sendto(b'hello', addr)

server.close()

#客户端
import socket

client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 8080)

client.sendto(b'hello server baby!', server_addr)
msg, addr = client.recvfrom(1024)
print(msg, addr)


# udp特点 >>> 无链接,类似于发短信,发了就行对方爱回不回,没有任何关系
# 将服务端关了,客户端起起来照样能够发数据。因为不需要考虑服务端能不能收到

# 验证udp协议有无粘包问题
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080))
print(server.recvfrom(1024))
print(server.recvfrom(1024))
print(server.recvfrom(1024))

import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1',8080)
client.sendto(b'hello',server_addr)
client.sendto(b'hello',server_addr)
client.sendto(b'hello',server_addr)

基于UDP实现简易版本的qq

# 服务端
import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))
while True:
    msg, addr = server.recvfrom(1024)
    print(addr)
    print(msg.decode('utf-8'))
    info = input('>>>:').encode('utf-8')
    server.sendto(info, addr)

server.close()

# 多个客户端
import socket

client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 8080)

while True:
    info = input('>>>:')
    info = ('来自客户端1的消息:%s'%info).encode('utf-8')  # 改中文备注即可
    client.sendto(info, server_addr)
    msg, addr = client.recvfrom(1024)
    print(msg.decode('utf-8'), addr)

client.close()

小知识点补充:

windows电脑和max电脑的时间同步功能,其实就是基于udp朝windows,max服务器发送请求获取标准时间

总结:

TCP协议就类似于打电话

UDP协议就类似于发短信

SocketServer模块介绍(让tcp也能支持并发)

并发

SocketServer模块
    1.能够实现并发效果
        并发:看起来像同时运行就能称之位并发
    
    2.udp在使用的时候,多个客户端要有一些io操作
        不然容易卡死
# TCP socketserver使用
import socketserver
class MyTcpServer(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                data = self.request.recv(1024)  # 对于tcp,self.request相当于conn对象
                if len(data) == 0:break
                print(data)
                self.request.send(data.upper())
            except ConnectionResetError:
                break
if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTcpServer)
    server.serve_forever()

# UDP socketserver使用
import socketserver


class MyUdpServer(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            data, sock = self.request
            print(data)
            sock.sendto(data.upper(), self.client_address)


if __name__ == '__main__':
    server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyUdpServer)
    server.serve_forever()

并发编程

操作系统的发展史

输入输出设备>>>:IO操作即(input和output)

  • 手工操作穿孔卡片

    程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
    
    手工操作方式两个特点:
      (1)用户独占全机。不会出现因资源已被其他用户占用而等待的现象,但资源的利用率低。
      (2)CPU 等待手工操作。CPU的利用不充分。
  • 批处理(磁带)

1572538-20190505143345971-1955447173.png


主机与输入机之间增加一个存储设备——磁带,在运行于主机上的监督程序的自动控制下,计算机可自动完成:成批地把输入机上的用户作业读入磁带,依次把磁带上的用户作业读入主机内存并执行并把计算结果向输出机输出。完成了上一批作业后,监督程序又从输入机上输入另一批作业,保存在磁带上,并按上述步骤重复处理。
监督程序不停地处理各个作业,从而实现了作业到作业的自动转接,减少了作业建立时间和手工操作时间,有效克服了人机矛盾,提高了计算机的利用率。
但是,在作业输入和结果输出时,主机的高速CPU仍处于空闲状态,等待慢速的输入/输出设备完成工作: 主机处于“忙等”状态。
  • 脱机批处理系统

1572538-20190505143404076-1513711386.png

  卫星机:一台不与主机直接相连而专门用于与输入/输出设备打交道的。
  其功能是:
  (1)从输入机上读取用户作业并放到输入磁带上。
  (2)从输出磁带上读取执行结果并传给输出机。
  这样,主机不是直接与慢速的输入/输出设备打交道,而是与速度相对较快的磁带机发生关系,有效缓解了主机与设备的矛盾。主机与卫星机可并行工作,二者分工明确,可以充分发挥主机的高速计算能力。
      脱机批处理系统:20世纪60年代应用十分广泛,它极大缓解了人机矛盾及主机与外设的矛盾。
  不足:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。
为改善CPU的利用率,又引入了多道程序系统。

一步步的优化,其实都是在提高计算机CPU利用率的问题(问题在于时串行并且没有空间上的复用)

多道技术的产生

解决cpu在执行程序,遇到io时,不干活的情况

串行:一个程序完完整整的运行完毕,才能运行下一个程序

并发:看上去像同时运行

多道技术:

所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。

1572538-20190505143419290-1273093677.png

在A程序计算时,I/O空闲, A程序I/O操作时,CPU空闲(B程序也是同样);必须A工作完成后,B才能进入内存中开始工作,两者是串行的,全部完成共需时间=T1+T2。

1572538-20190505143430629-1431634393.png

将A、B两道程序同时存放在内存中,它们在系统的控制下,可相互穿插、交替地在CPU上运行:当A程序因请求I/O操作而放弃CPU时,B程序就可占用CPU运行,这样 CPU不再空闲,而正进行A I/O操作的I/O设备也不空闲,显然,CPU和I/O设备都处于“忙”状态,大大提高了资源的利用率,从而也提高了系统的效率,A、B全部完成所需时间<<T1+T2。

​ 多道程序设计技术不仅使CPU得到充分利用,同时改善I/O设备和内存的利用率,从而提高了整个系统的资源利用率和系统吞吐量(单位时间内处理作业(程序)的个数),最终提高了整个系统的效率。

  单处理机系统中多道程序运行时的特点:

  (1)多道:计算机内存中同时存放几道相互独立的程序;

  (2)宏观上并行:同时进入系统的几道程序都处于运行过程中,即它们先后开始了各自的运行,但都未运行完毕;

  (3)微观上串行:实际上,各道程序轮流地用CPU,并交替运行。

多道程序系统的出现,标志着操作系统渐趋成熟的阶段,先后出现了作业调度管理、处理机管理、存储器管理、外部设备管理、文件系统管理等功能。

由于多个程序同时在计算机中运行,开始有了空间隔离的概念,只有内存空间的隔离,才能让数据更加安全、稳定。

出了空间隔离之外,多道技术还第一次体现了时空复用的特点,遇到IO操作就切换程序,使得cpu的利用率提高了,计算机的工作效率也随之提高。

  • 空间上的复用(多个程序共一套硬件设备,它是多道技术实现时间上的复用的基础,不然还要去硬盘读数据)
  • 时间上的复用(单个cpu的电脑上,起多个应用程序。cpu快速切换,给人的感觉是同时运行)
  • 一个任务占用cpu时间过长或被操作系统强行剥夺走cpu的执行权限(比起串行效率反而降低)
  • 一个任务执行过程中遇到io操作,也会被操作系统强行剥夺走cpu的执行权限(比起串行效率提高)

    并发:看上去像同时进行的(单核cpu)
    并行:同时运行(多核cpu)
    补充:单核的计算机不可能实现并行!

转载于:https://www.cnblogs.com/huangxuanya/p/10812891.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值