PythonNET网络编程4
本地套接字
Linux 文件
b(块设备文件) c(字符设备文件) d(目录)
-(普通文件) l(链接) s(套接字) p(管道)作用:用于本地不同的程序间进行通信
创建流程
- 创建本地套接字
sockfd = socket(AF_UNIX,SOCK_STREAM) - 绑定本地套接字文件
- 选定文件位置和名称
sockfd.bind(path)
- 选定文件位置和名称
- 创建本地套接字
监听
listen()消息收发
recv send
os.path.exists(path)
功能 : 判断一个文件是否存在
参数:目标文件
返回值 : 存在返回True 否则 False
os.remove() os.unlink()
功能 : 删除一个文件
参数 : 目标文件
# 接收端
from socket import *
import os
#确定套接字文件
sock_file = './sock_file'
#判断文件是否已经存在
if os.path.exists(sock_file):
os.remove(sock_file)
#创建本地套接字
sockfd = socket(AF_UNIX,SOCK_STREAM)
#绑定套接字文件
sockfd.bind(sock_file)
#监听
sockfd.listen(3)
#消息收发
while True:
c,addr = sockfd.accept()
while True:
data = c.recv(1024)
if data:
print(data.decode())
c.send(b"Receive")
else:
break
c.close()
sockfd.close()
# 客户端
from socket import *
#确保通信两端用的是同一个套接字文件
sock_file = "./sock_file"
#创建本地套接字
sockfd = socket(AF_UNIX,SOCK_STREAM)
#连接另一端
sockfd.connect(sock_file)
#收发消息
while True:
msg = input(">>")
if msg:
sockfd.send(msg.encode())
print(sockfd.recv(1024).decode())
else:
break
sockfd.close()
多任务编程
- 定义:通过应用程序利用计算机的多个核心达到同时执行多个任务的目的,一次提高计算机运行效率。
- 意义:充分利用计算机的资源提高程序的运行效率
- 实施方案:多进程、多线程
- 并行:多个计算机核心在同时处理多个任务,这时多个任务间是并行关系。
- 并发:同时处理多个任务,内核在多个任务间不断的切换,达到好像都在处理运行的效果。但实际一个时间点内核只能处理其中一个任务。
进程(Process)
定义:程序在计算机中的一次运行过程
程序:是一个可执行的文件,是静态的占有磁盘空间,不占有计算机的运行资源
进程:进程是一个动态过程的描述,占有计算机的资源,有一定的生命周期
同一个程序的不同运行过程是不同的进程,占用资源和生命周期都不一样。
进程的创建流程
- 用户空间通过运行程序或者调用接口发起创建进程
- 操作系统接受用户请求,开始创建进程
- 操作系统分配计算机资源,确定进程状态,开辟进程空间等工作
- 操作系统将创建好的进程提供给应用程序使用
CPU时间片
- 如果一个进程占有计算机核心,我们称为改进程占有计算机CPU时间片。
多个任务之间是争夺cpu的关系
谁占有cpu最终是操作系统决定
PCB(进程控制块)
- 在内存中开辟的一块空间,用来记录进程的信息
进程控制块是操作系统查找识别进程的标志 - 进程信息:ps -aux
PID(process ID)
- 在操作系统中每个进程都有一个唯一的ID号用来区别于其他进程。ID号由操作系统自动分配,是一个大于0的整数
父子进程
- 在系统中除了初始化进程,每一个进程都有一个父进程,可能有0个或者多个子进程。由此形成父子进程关系。
- 查看进程树
pstree - 查看父进程PID
ps -ajx
进程的状态
三态
- 就绪态:进程具备执行条件,等待系统分配资源
- 运行态:进程占有cpu处于运行状态
- 等待态:进程暂时不具备执行条件,阻塞等待满足条件后再执行
五态 (三态基础上增加新建态,终止态)
- 新建态:创建一个新的进程,获取资源的过程
- 终止态:进程执行结束,资源释放回收的过程
STAT 状态类别
S 等待态 (可中断等待)
D 等待态 (不可中断等待)
T 等待态 (暂停状态)
R 运行态 (包含就绪态)
Z 僵尸进程
< 高优先级进程
N 优先级较低
l 有子进程的
s 会话组组长
+ 前台进程
进程优先级
作用:决定了一个进程的执行权限和占有资源的优先程度
查看进程优先级
top 动态查看系统中的进程信息, 用<>翻页
取值范围 -20 -- 19 -20优先级最高使用指定的优先级运行程序
nice:指定运行的优先级e.g. nice -9 ./while.py 以优先级9运行
nice --9 ./while.py 以-9优先级运行
进程特征
- 进程之间运行互不影响,各自独立运行
- 进程是操作系统资源分配的最小单位
- 每个进程空间独立,各自占有一定的虚拟内存
要求
- 什么是进程,进程和程序的区别
- 了解进程特征
- 清楚进程每种状态,以及状态之间的转换关系
多进程编程
import os
pid = os.fork()
- 功能:创建新的进程
- 参数:无
- 返回值:
- 失败:返回一个负数
- 成功:在原有进程中返回新的进程的PID号,在新的进程中返回0
import os
from time import sleep
print("*******************")
a = 1
pid = os.fork()
if pid < 0:
print("创建进程失败")
elif pid == 0:
print("这是新的进程")
print("a = ",a)
a = 10000 # 始终在子进程中运行,不会干扰父进程
else:
sleep(1)
print("这是原有进程")
print("parent a =",a)
print("演示完毕")
# 至于谁现运行,看谁先抢到时间片
*******************
这是新的进程
a = 1
演示完毕
这是原有进程
parent a = 1
演示完毕
- 子进程会复制父进程全部代码段,包括fork之前产生的内存空间
- 子进程从fork的下一句开始执行,与父进程互不干扰
- 父子进程的执行顺序是不一定的,父子进程公用一个终端显示
- 父子进程通常会根据fork返回值得差异选择执行不同的代码。所以if结构几乎是fork的固定搭配
- 父子进程空间独立,操作的都是本空间的内容,互不影响
- 子进程也有自己的特性,比如PID号,PCB,命令集等
进程相关函数
os.getpid()
- 功能:获取当前进程的进程号
- 返回值:返回进程号
os.getppid()
- 功能:获取当前进程父进程的PID号
- 返回值:返回进程号
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("Create process failed")
elif pid == 0:
sleep(1)
#获取当前进程的PID
print("Child get pid:",os.getpid())
#获取父进程的PID
print("Child get parent pid:",os.getppid())
else:
sleep(1)
print("parent get child pid:",pid)
print("parent get pid:",os.getpid())
parent get child pid: 1219
parent get pid: 832
Child get pid: 1219
Child get parent pid: 832
os._exit(status)
- 功能:进程退出
- 参数:进程的退出状态
sys.exit([status])
- 功能:进程退出
- 参数:数字表示退出状态,不写默认为0,字符串,表示退出时打印的内容
- sys.exit 可以通过捕获 SystemExit异常阻止退出
import os,sys
#结束进程后不在执行后面内容
# os._exit(0)
try:
sys.exit("hello world")
except SystemExit as e:
print("退出:",e)
print("process exit")
退出: hello world
process exit
孤儿进程
- 父进程先于子进程退出,此时子进程就称为孤儿进程
孤儿进程会被操作系统指定的进程收养,系统进程就成为孤儿进程的新的父进程
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("Create process failed")
elif pid == 0:
sleep(1)
#获取当前进程的PID
print("Child get pid:",os.getpid())
#获取父进程的PID
print("Child get parent pid:",os.getppid())
else:
print("parent get child pid:",pid)
print("parent get pid:",os.getpid())
(base) EnweiHaos-MacBook-Pro:Day4 haoen110$ python fo.py
parent get child pid: 1216
parent get pid: 1215
(base) EnweiHaos-MacBook-Pro:Day4 haoen110$ Child get pid: 1216
Child get parent pid: 1
|
僵尸进程
- 子进程先于父进程退出,但是父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程
僵尸进程会存留少量PCB信息在内存中,大量的僵尸进程会消耗系统资源,应该避免僵尸进程产生
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("create process failed")
elif pid == 0:
print("Child Process:",os.getpid())
print("Child process exit")
else:
print("parent process")
while True:
pass
parent process
Child Process: 1242
Child process exit
haoen110 1242 1241 1241 0 1 Z+ s002 0:00.00 (python3.7)
如何避免僵尸进程产生
pid,status = os.wait()
- 功能:
- 在父进程中阻塞等待处理子进程退出
- 返回值:
- pid 退出的子进程的PID号
- status 获取子进程退出状态
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("create process failed")
elif pid == 0:
sleep(3)
print("Child process exit",os.getpid())
os._exit(3)
else:
pid,status = os.wait()
print(pid,status)
print(os.WEXITSTATUS(status)) #获取子进程退出状态
while True:
pass
pid,status = os.waitpid(pid,option)
- 功能 :
- 在父进程中阻塞等待处理子进程退出
- 参数 :
- pid -1 表示等待任意子进程退出
- pid >0 表示等待对应PID号的子进程退出
- option 0 表示阻塞等待
- WNOHANG 表示非阻塞
- 返回值:
- pid 退出的子进程的PID号
- status 获取子进程退出状态
os.waitpid(-1,0) ===> os.wait()
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("create process failed")
elif pid == 0:
sleep(3)
print("Child process exit",os.getpid())
os._exit(3)
else:
while True:
sleep(1)
#通过非阻塞的形式捕获子进程退出
pid,status = os.waitpid(-1,os.WNOHANG)
print(pid,status)
print(os.WEXITSTATUS(status)) #获取子进程退出状态
while True:
pass
- 让父进程先退出
- 父进程创建子进程等待子进程退出
- 子进程创建二级子进程后立即退出
- 二级子进程称为孤儿,和原来的父进程各自执行事件
#创建二级子进程避免僵尸
import os
from time import sleep
def f1():
sleep(3)
print("第一件事")
def f2():
sleep(4)
print("第二件事")
pid = os.fork()
if pid < 0:
print('error')
elif pid == 0:
#创建二级子进程
p = os.fork()
if p == 0:
f2() #做第二件事
else:
os._exit(0)
else:
os.wait() #等一级子进程退出
f1() #做第一件事
写一个聊天室
功能:类似qq群聊
- 进入聊天室需要输入姓名,姓名不能重复
- 有人进入聊天室会向其他人发送通知
xxx 进入了聊天室 - 一个人发消息,其他人会收到消息
xxx 说 : xxxxxxxx - 某人退出聊天室,其他人也会收到通知
xxx 退出了聊天室 - 管理员喊话 服务端发送消息所有的客户端都就收到
管理员说 :xxxxxx
功能模型:转发
需要的技术:套接字通信 udp套接字
用户存储:字典或列表
消息收发的随意性:多进程
代码设计
- 封装 将每个功能封装为函数
- 接口测试(每实现一步就测试一步)
代码编写流程
- 搭建网络连接---> 创建多进程---> 每个进程功能编写---> 项目功能模块实现
登录
- 客户端:
- 输入姓名,将信息发给服务端(L name)
- 等待服务端回复,根据回复判断是否登录成功
- 服务端:
- 接收请求信息,判断请求类型
- 判断用户名是否存在,如果存在回复不能登录
- 如果不存在回复可以登录并插入到数据结构,发送通知给其他用户
- 客户端:
聊天
- 客户端:
- 创建父子进程,一个发,一个收!
- 发送聊天请求/接收聊天信息
- 服务端:
- 接收请求信息
- 将消息转发给其他客户端
- 客户端:
退出
管理员消息
#!/usr/bin/env python3
from socket import *
import os,sys
#登录判断
def do_login(s,user,name,addr):
if (name in user) or name == '管理员': # name in user 是判断键
s.sendto("该用户已存在".encode(),addr)
return
s.sendto(b'OK',addr)
#通知其他人
msg = "\n欢迎 %s 进入聊天室"%name
for i in user:
s.sendto(msg.encode(),user[i])
#插入用户
user[name] = addr
#转发聊天消息
def do_chat(s,user,name,text):
msg = "\n%s 说:%s"%(name,text)
for i in user:
if i != name:
s.sendto(msg.encode(),user[i])
#退出聊天室
def do_quit(s,user,name):
msg = '\n' + name + "退出了聊天室"
for i in user:
if i == name:
s.sendto(b'EXIT',user[i])
else:
s.sendto(msg.encode(),user[i])
#从字典删除用户
del user[name]
# 接收客户端请求
def do_parent(s):
#存储结构 {'zhangsan':('127.0.0.1',9999)}
user = {} # 创建字典
while True:
msg,addr = s.recvfrom(1024)
msgList = msg.decode().split(' ')
#区分请求类型
if msgList[0] == 'L':
do_login(s,user,msgList[1],addr) # 字典是可变类型,函数内部可以改变其内容
elif msgList[0] == 'C':
do_chat(s,user,msgList[1],\
' '.join(msgList[2:]))
elif msgList[0] == 'Q':
do_quit(s,user,msgList[1])
# 做管理员喊话
def do_child(s,addr): # 自己发送给父进程,父进程接收
while True:
msg = input("管理员消息:")
msg = 'C 管理员 ' + msg
s.sendto(msg.encode(),addr)
#创建网络,创建进程,调用功能函数
def main():
#server address
ADDR = ('0.0.0.0',9999)
#创建套接字
s = socket(AF_INET,SOCK_DGRAM) # 创建UDP套接字
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
#创建一个单独的进程处理管理员喊话功能
pid = os.fork()
if pid < 0:
sys.exit("创建进程失败")
elif pid == 0:
do_child(s,ADDR)
else:
do_parent(s)
if __name__ == "__main__":
main()
# client
from socket import *
import sys,os
#发送消息
def send_msg(s,name,addr):
while True:
text = input("发言:")
#如果输入quit表示退出
if text.strip() == 'quit':
msg = 'Q ' + name
s.sendto(msg.encode(),addr)
sys.exit("退出聊天室")
msg = 'C %s %s'%(name,text)
s.sendto(msg.encode(),addr)
#接收消息
def recv_msg(s):
while True:
data,addr = s.recvfrom(2048)
if data.decode() == 'EXIT':
sys.exit(0)
print(data.decode() + "\n发言:",end="")
#创建套接字,登录,创建子进程
def main():
# 从命令行获取服务端地址
if len(sys.argv) < 3:
print("请在后面附上IP地址和端口,用空格隔开")
return
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
#创建套接字
s = socket(AF_INET,SOCK_DGRAM)
while True:
name = input("请输入姓名:")
msg = "L" + " " + name
#发送登录请求
s.sendto(msg.encode(),ADDR)
#等待服务器回复
data,addr = s.recvfrom(1024)
if data.decode() == 'OK':
print("您已进入聊天室")
break
else:
#不成功服务端会回复不允许登录原因
print(data.decode())
#创建父子进程
pid = os.fork()
if pid < 0:
sys.exit("创建子进程失败")
elif pid == 0:
send_msg(s,name,ADDR)
else:
recv_msg(s)
if __name__ == "__main__":
main()
PythonNET网络编程4的更多相关文章
- PythonNET网络编程1
# PythonNET 网络编程 ISO(国际标准化组织) 制定了 OSI(Open System Interconnectio),意为开放式系统互联.国际标准化组织(ISO)制定了OSI模型,该模型 ...
- PythonNET网络编程3
IO IO input output 在内存中存在数据交换的操作都可以认为是IO操作 和终端交互 : input print 和磁盘交互 : read write 和网络交互 : recv send ...
- PythonNET网络编程2
UDP应用:广播 广播:一点发送,多点接收 广播地址:一个网段内有一个指定的广播地址,是该网段的最大地址 192.168.2.255 广播风暴:一个网络中有大量的广播就会产生广播风暴占用大量带宽,影响 ...
- 猫哥网络编程系列:HTTP PEM 万能调试法
注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...
- python select网络编程详细介绍
刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程 一.socket模块 socket - Low- ...
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- 猫哥网络编程系列:详解 BAT 面试题
从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...
- 浅谈C#网络编程(一)
阅读目录: 基础 Socket编程 多线程并发 阻塞式同步IO 基础 在现今软件开发中,网络编程是非常重要的一部分,本文简要介绍下网络编程的概念和实践. Socket是一种网络编程接口,它是对传输层T ...
- C++11网络编程
Handy是一个简洁优雅的C++11网络库,适用于linux与Mac平台.十行代码即可完成一个完整的网络服务器. 下面是echo服务器的代码: #include <handy/handy.h&g ...
随机推荐
- 127.0.0.1和localhost和本机IP三者的区别!
1, 先来说下回送地址(Loopback Address): 回送地址是主机用于向自身发送通信的一个特殊地址(也就是一个特殊的目的地址).可以这么说:同一台主机上的两项服务若使用回送地址而非分配的主机 ...
- Linux下yum安装ffmpeg和使用
本文属于转载文章:转载地址是http://www.cnblogs.com/dennisit/archive/2012/12/27/2835089.html 使用Yum安装ffmpeg 打开 vi /e ...
- 使用 docker 安装多版本的 MySQL
原文:使用 docker 安装多版本的 MySQL 首先从 docker 官网下载安装 docker. 检查 docker 安装是否成功,出现类似下面的信息就是安装好了 $ docker versio ...
- 使用Linux遇到的一些问题和解决方案
1.如何在重装系统或换机器以后继续使用以前用过的thunderbird邮件 执行命令thunderbird -ProfileManager以后会打开一个配置用户界面. 在里面添加一个新的配置,然后选择 ...
- You have ettempted to queue to many files.You may select one files.
<script type="text/javascript" src="/script/swfupload/swfupload.js"></s ...
- Eclipse中JDK的配置
window -> preference -> java -> install jres -> add -> standard vm -> 设置好相应的jre ho ...
- sessionStorage的使用方法
本篇是关于sessionStorage的使用方法的介绍,简单几行代码,实现sessionStorage,请大家查阅 (1)在需要设置sessionStorage的页面写如下代码可以存入sessionS ...
- chsh---更换登录系统时使用的shell
chsh命令 chsh命令用来更换登录系统时使用的shell.若不指定任何参数与用户名称,则chsh会以应答的方式进行设置. 语法 chsh(选项)(参数) 选项 -s<shell 名称&g ...
- 微信小程序从零开始开发步骤(七)引入外部js 文件
上一章讲到小程序页面的四种常见的跳转的方法,这一章写如何引入一个外部的js文件,既utils文件夹的用处,其实步骤很简单: 1:准备好外部想要引入的外部文件,命名为util.js,并且填充固定的文件内 ...
- java bigdecimal (java double也时会失真)
BigDecimal加减乘除运算 2011-11-21 21:22 6470人阅读 评论(0) 收藏 举报 stringdivjavaup工具 java.math.BigDecimal.BigDeci ...