今日内容
上节课复习: 1、粘包问题 tcp协议的的nagle算法会将,数据量较小,并且发送时间间隔较端的多个数据包合并为一个发送 2、如何解决粘包问题? 自定义报头 今日内容: 1、基于udp协议的套接字通信 2、socketserver模块 3、操作系统的发展史=>多道技术(******) 4、什么是进程?为何要用进程?开启进程的两种方式?
操作系统原理
1、串行: 一个任务完完整整地运行完毕后,才能运行下一个任务 2、并发 看起来多个任务是同时运行的即可,单核也可以实现并发 3、并行: 真正意义上多个任务的同时运行,只有多核才实现并行 4、cpu的功能: cpu是用来做计算,cpu是无法执行IO操作的,一旦遇到io操作,应该让cpu去执行别的任务 5、多道技术 1、空间上的复用=》多个进程共用一个内存条 2、时间上的复用-》多个进程复用同一个cpu的时间 cpu遇到IO切换:可以提升效率 一个进程占用cpu时间过长也会切走:为了实现并发效果不得已而为之,反而会降低程序的执行效率 第三代计算机的操作系统广泛应用了第二代计算机的操作系统没有的关键技术:多道技术 cpu在执行一个任务的过程中,若需要操作硬盘,则发送操作硬盘的指令,指令一旦发出,硬盘上的机械手臂滑动读取数据到内存中, 这一段时间,cpu需要等待,时间可能很短,但对于cpu来说已经很长很长,长到可以让cpu做很多其他的任务, 如果我们让cpu在这段时间内切换到去做其他的任务,这样cpu不就充分利用了吗。这正是多道技术产生的技术背景 多道技术: 多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一个资源(比如cpu)的有序调度问题, 解决方式即多路复用,多路复用分为时间上的复用和空间上的复用。 空间上的复用:将内存分为几部分,每个部分放入一个程序,这样,同一时间内存中就有了多道程序。 时间上的复用:当一个程序在等待I/O时,另一个程序可以使用cpu,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%, 类似于我们小学数学所学的统筹方法。(操作系统采用了多道技术后,可以控制进程的切换,或者说进程之间去争抢cpu的执行权限。 这种切换不仅会在一个进程遇到io时进行,一个进程占用cpu时间过长也会切换,或者说被操作系统夺走cpu的执行权限) 现代计算机或者网络都是多用户的,多个用户不仅共享硬件,而且共享文件,数据库等信息,共享意味着冲突和无序。 操作系统主要使用来 1.记录哪个程序使用什么资源 2.对资源请求进行分配 3.为不同的程序和用户调解互相冲突的资源请求。 我们可将上述操作系统的功能总结为:处理来自多个程序发起的多个(多个即多路)共享(共享即复用)资源的请求,简称多路复用 多路复用有两种实现方式 1.时间上的复用 当一个资源在时间上复用时,不同的程序或用户轮流使用它,第一个程序获取该资源使用结束后,在轮到第二个。。。第三个。。。 例如:只有一个cpu,多个程序需要在该cpu上运行,操作系统先把cpu分给第一个程序,在这个程序运行的足够长的时间 (时间长短由操作系统的算法说了算)或者遇到了I/O阻塞,操作系统则把cpu分配给下一个程序,以此类推, 直到第一个程序重新被分配到了cpu然后再次运行,由于cpu的切换速度很快,给用户的感觉就是这些程序是同时运行的,或者说是并发的, 或者说是伪并行的。至于资源如何实现时间复用,或者说谁应该是下一个要运行的程序,以及一个任务需要运行多长时间,这些都是操作系统的工作。 2.空间上的复用 每个客户都获取了一个大的资源中的一小部分资源,从而减少了排队等待资源的时间。 例如:多个运行的程序同时进入内存,硬件层面提供保护机制来确保各自的内存是分割开的,且由操作系统控制,这比一个程序独占内存一个一个排队进入内存效率要高的多。 有关空间复用的其他资源还有磁盘,在许多系统中,一个磁盘同时为许多用户保存文件。分配磁盘空间并且记录谁正在使用哪个磁盘块是操作系统资源管理的典型任务。 这两种方式合起来便是多道技术 空间上的复用最大的问题是:程序之间的内存必须分割,这种分割需要在硬件层面实现,由操作系统控制。如果内存彼此不分割,则一个程序可以访问另外一个程序的内存, 首先丧失的是安全性,比如你的qq程序可以访问操作系统的内存,这意味着你的qq可以拿到操作系统的所有权限。 其次丧失的是稳定性,某个程序崩溃时有可能把别的程序的内存也给回收了,比方说把操作系统的内存给回收了,则操作系统崩溃。
操作系统的两大功能
操作系统的两大功能: #一:隐藏了丑陋的硬件调用接口,为应用程序员提供调用硬件资源的更好,更简单,更清晰的模型(系统调用接口)。 应用程序员有了这些接口后,就不用再考虑操作硬件的细节,专心开发自己的应用程序即可。 例如:操作系统提供了文件这个抽象概念,对文件的操作就是对磁盘的操作,有了文件我们无需再去考虑关于磁盘的读写控制(比如控制磁盘转动,移动磁头读写数据等细节), #二:将应用程序对硬件资源的竞态请求变得有序化 例如:很多应用软件其实是共享一套计算机硬件,比方说有可能有三个应用程序同时需要申请打印机来输出内容,那么a程序竞争到了打印机资源就打印, 然后可能是b竞争到打印机资源,也可能是c,这就导致了无序,打印机可能打印一段a的内容然后又去打印c...,操作系统的一个功能就是将这种无序变得有序。
进程
1、什么是进程 进程指的就是一个正在运行的程序,或者说是程序的运行过程,即进程是一个抽象的概念 进程是起源于操作系统的,是操作系统最核心的概念,操作系统所有其他的概念都是围绕进程展开的 多道技术 2、为何要进程 并发 3、如何用进程 开启进程的两种方式
基于udp协议的套接字(qq)
import socket server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp server.bind(('127.0.0.1',8080)) while True: data,client_addr=server.recvfrom(1024) print('===>',data,client_addr) server.sendto(data.upper(),client_addr) server.close()
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp while True: msg=input('>>: ').strip() #msg='' client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) data,server_addr=client.recvfrom(1024) print(data) client.close()
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp while True: msg=input('>>: ').strip() #msg='' client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) data,server_addr=client.recvfrom(1024) print(data) client.close()
udp协议没有粘包问题
import socket server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp server.bind(('127.0.0.1',8080)) data,client_addr=server.recvfrom(1) #b'hello'==>b'h' print('第一次:',client_addr,data) data,client_addr=server.recvfrom(1024) #b'world' =>b'world' print('第二次:',client_addr,data) # # data,client_addr=server.recvfrom(1024) # print('第三次:',client_addr,data) server.close()
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp client.sendto('hello'.encode('utf-8'),('127.0.0.1',8080)) client.sendto('world'.encode('utf-8'),('127.0.0.1',8080)) # client.sendto(''.encode('utf-8'),('127.0.0.1',8080)) client.close()
UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。
udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y>x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠
基于socketserver实现并发socket(基于udp协议)
import socketserver class MyHandler(socketserver.BaseRequestHandler): def handle(self): #通信循环 # print(self.client_address) # print(self.request) data=self.request[0] print('客户消息',data) self.request[1].sendto(data.upper(),self.client_address) if __name__ == '__main__': s=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyHandler) s.serve_forever()
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp while True: # msg=input('>>: ').strip() #msg='' msg='client444444' client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) data,server_addr=client.recvfrom(1024) print(data) client.close()
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报协议-》udp while True: # msg=input('>>: ').strip() #msg='' msg='client1111' client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) data,server_addr=client.recvfrom(1024) print(data) client.close()
基于socketserver实现并发socket(基于tcp协议)
import socketserver class MyHandler(socketserver.BaseRequestHandler): def handle(self): #通信循环 while True: # print(self.client_address) # print(self.request) #self.request=conn try: data=self.request.recv(1024) if len(data) == 0:break self.request.send(data.upper()) except ConnectionResetError: break if __name__ == '__main__': s=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyHandler,bind_and_activate=True) s.serve_forever() # 代表连接循环 # 循环建立连接,每建立一个连接就会启动一个线程(服务员)+调用Myhanlder类产生一个对象,调用该对象下的handle方法,专门与刚刚建立好的连接做通信循环
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8080)) # 指定服务端ip和端口 while True: # msg=input('>>: ').strip() #msg='' msg = 'client33333' # msg='' if len(msg) == 0:continue phone.send(msg.encode('utf-8')) data=phone.recv(1024) print(data) phone.close()
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8080)) # 指定服务端ip和端口 while True: # msg=input('>>: ').strip() #msg='' msg='client11111'#msg='' if len(msg) == 0:continue phone.send(msg.encode('utf-8')) data=phone.recv(1024) print(data) phone.close()