1、C/S B/S
client<---基于网络通信--->server
browser<---基于网络通信--->server
server 端必须满足的条件
1、稳定运行(网络、硬件、操作系统、服务端应用软件),对外一直提供服务
2.服务端必须绑定一个固定的地址
什么是互联网
两大要素
底层的物理连接介质,是为通信铺好道路的
一套统一的通信标准---》互联网通信协议
互联网协议就是计算机界的英语
自定义协议:
任何一种通信协议都必须包含两部分
1、报头:必须是固定长度
2. 数据
标识地址的方式:
ip+mac 就能标识全世界范围内独一无二的一台计算机
ip+mac+port 就能标识全世界范围内独一无二的一个基于网络通信的应用软件
url地址:标识全世界范围内独一无二的一个资源
OSI 五层协议 了解
tcp、协议
三次握手建立连接
四次挥手断开连接
1、为何建连接要三次而断开连接却需要四次
2、为何tcp协议是可靠协议,而udp协议是不可靠协议
3、tcp协议建立连接与断开连接的状态信息以及表示的意义
半连接:
限制的是同一时刻的请求数,而非连接数
tcp 协议粘包问题分析
#服务端
from socket import *
server=socket(AF_INET,SOck_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
conn,addr=server.accept()
print('第一次;',res1)
res2=conn.recv(1024)
print('第二次;',res2)
res3=conn.recv(1024)
print('第三次;',res3)
客户端
from socket import *
import time
client=socket(AF_INET,SOCK_STREAM)
client=connect('127.0.0.1',8080)
client.send(b'htime.sleeclient.send(b'world')
time.sleep(0.2)
client.send(b'egon'
模拟ssh远程执行命令
#服务端
from socket import *
import subprocess
import struct
server=socket(AF_INET,SOCK_STREAM)
server.bind(tupel_host_port)
server.listen(5)
while True:
conn,client_addr=server.accpt()
print('新的客户端',client_addr)
while True:
try:
cmd=conn.recv(1025)
if len(cmd)==0:break
obj=subprocees.Popen(cmd.decode(encoding='utf-8'),
shell=True,
stderr=subprocess.PIPE,
stout=subprocess.PIPE)
stout=obj.stdout.read()
sterr=obj.stderr.read()
#先制作表头 固定长度
total_size=len(stdout)+len(stderr)
header=struct.pack('i',total_size)
#发送固定长度的报头
conn.send(header)
#在发送真实数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
#客户端
from socket import *
import struct
client=socket(AF_INET,SOCK_STREAM)
client.connect(tuple_host_port)
while True:
cmd=input('>>:').strip()
if len(cmd)==0:continue
client.send(cmd.encode('utf-8'))
#先收固定长度的报头
header=client.recv(4)
#从报头中解析对数据的描述信息
total_size=struct.unpack('i',header)[0]
#收真实的数据
recv_size=0
res=b''
while recv_size total_size:
data=client.recv(1024)
res+=data
recv_size+=len(data)
print(res.decode(encoding='gbk'))
终极版 粘包问题解决
from socket import *
import subprocess
import struct
import json
server=socket(AF_INEF,SOCK_STREAM)
server.bind(tuple_host_port)
server.listen(5)
while True:
conn,client_addr=conn.recv(1024)
print('新的客户端',client_addr)
while True:
try:
cmd=conn.recv(1024)
if len(cmd)==0:break
运行系统命令
obj=subporcess.Popean(cmd.decode(encoding='utf-8'),sheel=True,
stderr=subprocess.PIPE,
stdout=subporcess.PIPE)
s_out=obj.stdout.read()
s_err=obj.stderr.read()
header_dir={
'file_name':'a.txt',
'total_size':len(s_out)+len(s_err) ,
'hash':'sdfsd'
}
先把报头的长度len(header_bytes)打包成4个bytes,然后发送出去
conn.send(struct.pack('i',len(header_bytes)))
发送报头
conn.send(header_bytes)
在发送真实的数据
conn.send(s_out)
conn.send(s_err)
except ConnectionResetError:
break
conn.close()
客户端
from socket import *
import struct
import json
client=socket(AF_INET,SOCK_STREAM)
client.connect(tuple_host_port)
while True:
cmd=input('>>:').strip()
if len(cmd)==0:continue
client.send(cmd.encode('utf-8'))
先收4个字节,该4字节中包含报头的长度
header_len=struct.unpack('i',client.recv(4))[0]
2/在接收报头
header_bytes=client.recv(header_len)
从报头中解析出想要的内容
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
print(header_dic)
total_size=header_dic['total_size']
在收真实的数据
recv_size=0
res=b''
while recv_size < total_size:
data=client.recv(1024)
res+=data
recv_size+=len(data)
print(res.decode(encoding='gbk'))
什么是套接字:
套接字位于应用层与传输层之间,将传输层以下的协议都封装了接口
对于应用层来说只需要调用套接字的接口,写出的程序自然是遵循tcp或udp
c/s
server 必须遵循
稳定运行,对外一直提供服务
服务必须绑定ip和端口
上节课复习:
1 粘包问题:
tcp协议的nagle算法会将,数据量较小,并且发送时间间隔教短的多个数据包合并为一个发送
2.如何解决粘包问题?
自定义报头
今日内容:
1、基于udp 协议的套接字通信
2.socketserver模块
3.操作系统的发展史=》多道技术*****
4.什么是进程?为什么要用进程,开启进程的两种方式
操作系统原理:
1 串行:一个任务完完整整地运行完毕后,才能运行下一个任务
2 并发:看起来多个任务是同时运行的即可,单核也可以实现并发
3 并行:真正意义上多个任务的同时运行,只有多核才实现并行
4 cpu的功能
cpu是用来做计算,cpu是无法执行IP操作,一旦遇到io操作,应该让cpu去执行别的任务
多道技术
1.空间上的复用==》多个进程共用一个内存条
2.时间上的复用==》多个进程复用同一个cpu时间
cpu遇到io切换:可以提升效率
一个进程占用cpu时间过长也会被切走:
为了实现并发效果不得已而为之,反而会降低程序的执行效率
什么是进程:
进程指的是:一个正在运行的程序,或者说是程序的运行过程,即进程是一个抽象的概念
进程是起源于操作系统的,是操作系统最核心的概念,操作系统所有其他的概念都是围绕进程展开的
多道技术:
为何要进程:
并发
如何用进程:
开启进程的两种方式
udp
udp协议没有粘包问题
#服务端
import socket
server =socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#称为数据报协议==》upp
server.bind(tuple_host_port)
data,client_addr=server.recvfrom(1)
print('第一次',clent_addr,data)
data,client_add=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()
#基于socketserver 实现并发的socket(基于tcp协议)
#socketserver 方法实现 服务端
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__name=='__main__':
s=socketserver.ThreadingTCPServer(tuple_host_port,Myhandler,bind_and_active=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()
#基于socketserver 实现并发的socket(基于udp协议)
import socketserver
class MyHandler(socketserver.BaseRequsetHandler)
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(tuple_host_port,MyHandler)
s.serve_forver()
#用了这个客户端就可以多开,并且实现并发操作,Threadserve_forever,这里封装好的接口,底层是Thread,猜测:是基于线程实现的
#udp 客户端
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()
基于udp协议的套接字
#udp、 服务端
import socket
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#数据协议 --》udp
server.bind(tuple_host_port)
while True:
data,client_addre=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)#数据报协议
while True:
msg=input('>>:').strip()
client.sendto(msg.encode('utf-8'),host_port_tuple)
print(data)
client.close()
上节课复习:
1、操作系统(现代操作系统):
操作系统是位于计算机硬件与软件之间的控制程序
作用: 1。将硬件的复杂操作封装成简单的接口,给用户或者应用程序使用
2.将多个应用程序对硬件的竞争变得有序
2.进程
一个正在运行的程序,或者说是一个程序的运行过程
3.串行、并发、并行
串行:一个任务完完整整运行完毕,才执行下一个
并发:多个任务看起来是同时运行的,单核就可以实现并发
并行:多个任务是真正意义上的同时运行,只有多核才能实现并行
4.多道技术
背景:想要在单核下实现并发(单核同一时刻只能执行一个任务)
并发实现的本质就:切换+保存状态
多道技术:
1.空间上的复用=》多个任务共用一个内存条,但占用内存是彼此隔离的,而且是物理层面隔离的
2.时间上的复用=》多个任务共用同一个cpu
切换:
1.遇到io切换
2.一个任务占用cpu时间过长,或者有另外一个优先级更高的任务抢走cpu
今日内容:
进程理论
开启进程的两种方式
进程对象相关的属性或者方法
线程:
线程理论
开启线程的两种方式
先从对象相关的属性或方法
开启子进程的两种方式:
方式一:
from multiporcessing import Process
import time
def task(x):
print('%s is runing '%x)
time.sleep(3)
print('%s is done '%x)
if __name__=='__main__':
#两种写法:Process(target=task,kwargs={'x':'子进程'})
p=Process(target=task,args=('子进程',))## 如果args=(),括号内只有一个参数,一定记住加逗号
p.start()#只是在向操作系统发送一个开启子进程的信号,#运行起来取决于操作系统
print('主')
from multiprocessing import process
import time
class Myporcess(Process):
def __init__(self,x):
super().__init__()
self.name=x
def run(self):
print('%s is runing '%self.name)
time.sleep(3)
print('%s is done '%self.name)
if __name__=='__main__':
p=Myprocess('子进程1')
p.start()#等同于p.run()
print('主')
from multiprocessing import Process
import time
def task(x,n):
print('%s is runing'%x)
time.sleep(n)
print('%s is done'%x)
if __name__=='__main__':
p1=Process(targest=task,args=('我是参数',3))# 如果args=(),括号内只有一个参数,一定记住加逗号
p2=Process(targest=task,args=('我是参数2',5))
p1.start() # 只是在操作系统发送一个开启子进程的信号
p2.start()
print('主‘)
进程内空间是彼此隔离的
from multiprocessing import Process
import time
x=100
def task():
global x
x=0
print('done')
if __name__ == '__main__':
p=Process(target=task)
p.start()
time.sleep(500) # 让父进程在原地等待,等了500s后,才执行下一行代码
print(x)
进程对象的方法或属性详解
#1、join
# from multiprocessing import Process
# import time
#
# def task(name):
# print('%s is running ' %name)
# time.sleep(3)
# print('%s is done ' % name)
#
#
# if __name__ == '__main__':
# p=Process(target=task,args=('子进程1',))
# p.start()
# p.join() # 让父进程在原地等待,等到子进程运行完毕后,才执行下一行代码
# print('主')
# from multiprocessing import Process
# import time
#
# def task(name,n):
# print('%s is running ' %name)
# time.sleep(n)
# print('%s is done ' % name)
#
#
# if __name__ == '__main__':
# p1=Process(target=task,args=('子进程1',1))
# p2=Process(target=task,args=('子进程2',2))
# p3=Process(target=task,args=('子进程3',3))
#
# start_time=time.time()
# p1.start()
# p2.start()
# p3.start()
#
# p3.join()
# p1.join()
# p2.join()
#
# stop_time=time.time()
# print('主',(stop_time-start_time))
# from multiprocessing import Process
# import time
#
# def task(name,n):
# print('%s is running ' %name)
# time.sleep(n)
# print('%s is done ' % name)
#
#
# if __name__ == '__main__':
# p1=Process(target=task,args=('子进程1',1))
# p2=Process(target=task,args=('子进程2',2))
# p3=Process(target=task,args=('子进程3',3))
#
# start=time.time()
# p1.start()
# p1.join()
# p2.start()
# p2.join()
# p3.start()
# p3.join()
#
# stop=time.time()
# print('主',(stop-start))
# from multiprocessing import Process
# import time
#
# def task(name,n):
# print('%s is running ' %name)
# time.sleep(n)
# print('%s is done ' % name)
#
#
# if __name__ == '__main__':
# # p1=Process(target=task,args=('子进程1',1))
# # p1.start()
# # p2=Process(target=task,args=('子进程2',2))
# # p2.start()
# # p3=Process(target=task,args=('子进程3',3))
# # p3.start()
#
# p_l=[]
# start=time.time()
# for i in range(1,4):
# p=Process(target=task,args=('子进程%s' %i,i))
# p_l.append(p)
# p.start()
#
# # print(p_l)
# for p in p_l:
# p.join()
#
# stop=time.time()
#
# print('主',(stop-start))
# pid
# from multiprocessing import Process
# import time
# import os
#
# def task(n):
# print('%s is running ' %os.getpid())
# time.sleep(n)
# print('%s is done ' % os.getpid())
#
#
# if __name__ == '__main__':
# p1=Process(target=task,args=(10,))
# # print(p1.pid)
# p1.start()
# print(p1.pid) # 父进程内查看子pid的方式
# print('主')
from multiprocessing import Process
import time
import os
def task():
print('自己的id:%s 父进程的id:%s ' %(os.getpid(),os.getppid()))
time.sleep(200)
if __name__ == '__main__':
p1=Process(target=task)
p1.start()
print('主',os.getpid(),os.getppid())
# 爹=》主--》儿子
# 了解
# from multiprocessing import Process,current_process
# import time
#
# def task():
# print('子进程[%s]运行。。。。' %current_process().name)
# time.sleep(200)
#
# if __name__ == '__main__':
# p1=Process(target=task,name='子进程1')
# p1.start()
# # print(p1.name)
# print('主')
# from multiprocessing import Process,current_process
# import time
#
# def task():
# print('子进程[%s]运行。。。。' %current_process().name)
# time.sleep(2)
#
# if __name__ == '__main__':
# p1=Process(target=task,name='子进程1')
# p1.start()
#
# # print(p1.is_alive())
# # p1.join()
# # print(p1.is_alive())
#
# p1.terminate()
# time.sleep(1)
# print(p1.is_alive())
# print('主')
什么是生产者消费者模式
生产者:比喻的是程序中负责产生数据的任务
消费者:比喻的是程序中负责处理数据的任务
生产者 -》共享的介质(队列)<--消费者
为何用
实现了生产者与消费者的解耦合,生产者可以不停地生产,消费者也可以不停地消费
从而平衡了生产者的生产能力与消费者的消费能力,提升了程序整体运行的效率
什么时候用?
当我们的程序中存在明显的两类任务,一类负责产生数据,另外一类负责处理数据
此时就应该考虑使用生产者消费者模型来提升程序的效率
'
# from multiprocessing import Queue,Process
# import time
# import os
# import random
#
# def producer(q):
# for i in range(10):
# res='包子%s' %i
# time.sleep(random.randint(1,3))
# # 往队列里丢
# q.put(res)
# print('\033[45m%s 生产了 %s[0m' %(os.getpid(),res))
# q.put(None)
#
# def consumer(q):
# while True:
# #从队列里取走
# res=q.get()
# if res is None:break
# time.sleep(random.randint(1,3))
# print('\033[46m%s 吃了 %s[0m' %(os.getpid(),res))
#
# if __name__ == '__main__':
# q=Queue()
# # 生产者们
# p1=Process(target=producer,args=(q,))
# # 消费者们
# c1=Process(target=consumer,args=(q,))
#
# p1.start()
# c1.start()
#
# print('主')
# from multiprocessing import Queue,Process
# import time
# import os
# import random
#
# def producer(name,food,q):
# for i in range(3):
# res='%s%s' %(food,i)
# time.sleep(random.randint(1,3))
# # 往队列里丢
# q.put(res)
# print('\033[45m%s 生产了 %s\033[0m' %(name,res))
# # q.put(None)
#
# def consumer(name,q):
# while True:
# #从队列里取走
# res=q.get()
# if res is None:break
# time.sleep(random.randint(1,3))
# print('\033[46m%s 吃了 %s\033[0m' %(name,res))
#
# if __name__ == '__main__':
# q=Queue()
# # 生产者们
# p1=Process(target=producer,args=('egon','包子',q,))
# p2=Process(target=producer,args=('杨军','泔水',q,))
# p3=Process(target=producer,args=('猴老师','翔',q,))
# # 消费者们
# c1=Process(target=consumer,args=('Alex',q,))
# c2=Process(target=consumer,args=('wupeiqidsb',q,))
#
# p1.start()
# p2.start()
# p3.start()
# c1.start()
# c2.start()
#
# p1.join()
# p2.join()
# p3.join()
# # 在p1\p2\p3都结束后,才应该往队列里放结束信号,有几个消费者就应该放几个None
# q.put(None)
# q.put(None)
# print('主')
from multiprocessing import JoinableQueue,Process
import time
import os
import random
def producer(name,food,q):
for i in range(3):
res='%s%s' %(food,i)
time.sleep(random.randint(1,3))
# 往队列里丢
q.put(res)
print('\033[45m%s 生产了 %s\033[0m' %(name,res))
# q.put(None)
def consumer(name,q):
while True:
#从队列里取走
res=q.get()
if res is None:break
time.sleep(random.randint(1,3))
print('\033[46m%s 吃了 %s[0m' %(name,res))
q.task_done()
if __name__ == '__main__':
q=JoinableQueue()
# 生产者们
p1=Process(target=producer,args=('egon','包子',q,))
p2=Process(target=producer,args=('杨军','泔水',q,))
p3=Process(target=producer,args=('猴老师','翔',q,))
# 消费者们
c1=Process(target=consumer,args=('Alex',q,))
c2=Process(target=consumer,args=('wupeiqidsb',q,))
c1.daemon=True
c2.daemon=True
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
p1.join()
p2.join()
p3.join()
q.join() #等待队列被取干净
# q.join() 结束意味着
# 主进程的代码运行完毕--->(生产者运行完毕)+队列中的数据也被取干净了->消费者没有存在的意义
# print('主')
守护进程
守护进程其实就是一个 子进程
守护=》伴随
守护进程会伴随主进程的代码运行完毕后而死掉
为何用守护进程
关键字就两个:
进程:当父进程需要将一个任务并发出去执行,需要将任务放到一个子进程里
守护:当该子进程内的代码在父进程代码运行完毕后就没有存在的意思了,就应该
将该子进程设置为守护进程,会在父进程代码结束后死掉
from multiporcessing import Process
import time,os
def task(name):
print('%s is runing '%name)
time.sleep(3)
if __name__=='__main__':
p1=Process(target=task,args=('守护进程',))
p2=Process(target=task,args='正常的子进程',)
p1.daemon=True #设置守护进程,一定要放在start 之前
p1.start()
p2.start()
print('主')
#主进程代码运行完毕,守护进程就会结束
from multiprocessing import Process
import time
def foo():
print(123)
time.sleep()
print('end 123')
def bar():
print('sdfsd')
time.sleep(3)
print('end456')
if __name__=='__main__':
p1=Process(target=foo)
p2=Process(target=bar)
p1.daemo=True
p1.start()
p2.start()
print('main-----')