一、tcp比udp真正可靠地原因
1.为什么tcp比udp传输可靠地原因:
我们知道在传输数据的时候,数据是先存在操作系统的缓存中,然后发送给客户端,在客户端也是要经过客户端的操作系统的,因为这个过程涉及到计算机硬件,也就是物理层的一些东西,那么tcp协议在确认客户端接收到完整的信息之后才会删除服务端操作系统中的缓存,否则就会继续发,这才是TCP协议的可靠性根本原因,而UDP只管发送数据而不管客户端有没有收到,所以就会造成丢包现象。
TCP UDP 的socket
1.基于tcp的套接字 无并发
服务端
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("localhost", 9909))
sock.listen(5)
while True:
conn, addr = sock.accept() # 有加上一个死循环(连接循环)
while True:
try: # 适应于window系统
data = conn.recv(1024) # 通讯循环
if not data: break # 适用于linux系统
print(data)
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
sock.close()
客户端
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 9909))
while True:
msg = input(">>>:").strip()
if not msg:
continue
client.send(msg.encode("utf8"))
data = client.recv(1024)
print(data.decode(\'utf8\'))
client.close()
这种情况下并没有并发效果,可以通过几个客户端连接到同一个服务端,所有的请求首先送到服务端半连接池,服务端再到伴了连接池取,
取出之后开始为第一个客户端服务,只要客户端不结束,那么就一直为客户端服务,不能为其他的客户端服务,其他的可以建成连接,但是没办法交互.
解决访问数量超过伴连接池报错问题 --->sock.listen(5)
2基于udp的套接字的收发消息
TCP:流逝协议
UDP:数据报协议
服务端:
import socket
sever=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sever.bind((ip))
while True:
client_data,client_addr=sever.recvfrom(1024)
sever.sendto(client_data.upper(),client_addr)
print(res)
客户端:
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
msg=input(\':\')
client.sendto((ip))
sever_data,sever_addr=client.recvfrom(1024)
print(sever_data,sever_addr)
UDP:可以在不开启服务端的情况下,发消息,调用的为SOCK_DGRAM。
UDP的特征:
数据报协议,自带报头,完整的数据报,所以UDP没有粘包现象,发与收一一对应,这一点与TCP是不一样的,
UDP来发消息,稳定可靠的数据量就是512kb,所以我们定义一个1024就够了。超过这个数就会容易造成丢包的现象,所以UDP一般用于数据量比较小的场景,比如我们平时聊天信息等
二、并发编程基础知识
1.是什么是进程?
顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。
进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展开的。
2.操作系统知识 -----> 操作系统理论知识请补充之!
3.总结
即使可以利用的cpu只有一个(早期的计算机确实如此),也能保证支持(伪)并发的能力。将一个单独的cpu变成多个虚拟的cpu(多道技术:时间多路复用和空间多路复用+硬件上支持隔离),没有进程的抽象,现代计算机将不复存在。
必备的理论知识:
一 操作系统的作用:
1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2:管理、调度进程,并且将多个进程对硬件的竞争变得有序
二 多道技术:
1.产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
cpu中的任意一个,具体由操作系统调度算法决定。
2.空间上的复用:如内存中同时有多道程序
3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
才能保证下次切换回来时,能基于上次切走的位置继续运行
4.并发编程之多进程
什么是进程
进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。
二 进程与程序的区别
程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。
举例:
想象一位有一手好厨艺的计算机科学家COOL正在为他的女儿元昊烘制生日蛋糕。
他有做生日蛋糕的食谱,
厨房里有所需的原料:面粉、鸡蛋、韭菜,蒜泥等。
在这个比喻中:
做蛋糕的食谱就是程序(即用适当形式描述的算法)
计算机科学家就是处理器(cpu)
而做蛋糕的各种原料就是输入数据。
进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等一系列动作的总和。
现在假设计算机科学家egon的儿子alex哭着跑了进来,说:Hey, Dad, my head got stung by a bee.
科学家COOL想了想,处理儿子alex蛰伤的任务比给女儿元昊做蛋糕的任务更重要,于是
计算机科学家就记录下他照着食谱做到哪儿了(保存进程的当前状态),然后拿出一本急救手册,按照其中的指示处理蛰伤。这里,我们看到处理机从一个进程(做蛋糕)切换到另一个高优先级的进程(实施医疗救治),每个进程拥有各自的程序(食谱和急救手册)。当蜜蜂蛰伤处理完之后,这位计算机科学家又回来做蛋糕,从他
离开时的那一步继续做下去。
需要强调的是:同一个程序执行两次,那也是两个进程,比如打开暴风影音,虽然都是同一个软件,但是一个可以播放苍井空,一个可以播放饭岛爱.
三 并发与并行
一 并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发
二 并行:同时运行,只有具备多个cpu才能实现并行
四 进程的创建
但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在。
而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式创建新的进程
系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
一个批处理作业的初始化(只在大型机的批处理系统中应用)
无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:
在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。
关于创建的子进程,UNIX和windows
1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。
2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于windows系统来说,从一开始父进程与子进程的地址空间就是不同的
六 进程的终止(了解)
1.正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
2.出错退出(自愿,python a.py中a.py不存在)
3.严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)
4.被其他进程杀死(非自愿,如kill -9)
七 进程的层次结构
无论UNIX还是windows,进程只有一个父进程,不同的是:
1.在UNIX中所有的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员。
2.在windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了。
八 进程的状态
tail -f access.log |grep \'404\'
执行程序tail,开启一个子进程,执行程序grep,开启另外一个子进程,两个进程之间基于管道\'|\'通讯,将tail的结果作为grep的输入。
进程grep在等待输入(即I/O)时的状态称为阻塞,此时grep命令都无法运行
其实在两种情况下会导致一个进程在逻辑上不能运行,
进程挂起是自身原因,遇到I/O阻塞,便要让出CPU让其他进程去执行,这样保证CPU一直在工作
与进程无关,是操作系统层面,可能会因为一个进程占用时间过多,或者优先级等原因,而调用其他的进程去使用CPU。
因而一个进程由三种状态