PythonNet_03_bj

前情回顾

tcp套接字
recv 函数从缓冲区取内容
send sendall 两者均可发送
粘包 :一次接收到多次发送的内容
处理粘包:加结束标志,构建消息结构,发送延迟

udp 套接字
无连接的不需要listen 和 accept
发送接收消息 sendto recvfrom

套接字属性
fileno() getpeername() setsockopt()

广播:一方发送多方接收

HTTP协议
请求类别 : GET POST PUT HEAD DELETE
响应情况 : 200 404


基础的http服务器
1.接收HTTP请求
2.给出一定的响应

01_HttpServer.py

from socket import *

#处理客户请求,返回响应
def handleClient(connfd):
#接收从浏览器发送的request请求
request = connfd.recv(4096)
# print(“")
# print(request)
# print("
”)
#列表=按行进行分割
requestHeadlers = request.splitlines()
for line in requestHeadlers:
print(line)

try:
    f = open("01_index.html",'r')
except IOError:
    #添加响应行
    response = "HTTP/1.1 404 not found\r\n"
    response += '\r\n'   #空行
    response += '====网页没找到===='  #相应体
else:
    response = "HTTP/1.1 200 OK\r\n"
    response += '\r\n'
    for i in f:
        response += i 
finally:
    connfd.send(response.encode())

#基础配置,功能函数的调用
def main():
#创建流式套接字
sockfd = socket()
#设置端口可重用
sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
#绑定IP和端口
sockfd.bind((“0.0.0.0”,8000))
#设置监听
sockfd.listen(10)
#
while True:
print(“Listen to the port 8000…”)
#等待接收连接请求
connfd,addr = sockfd.accept()
#调用handleClient函数处理请求
handleClient(connfd)
connfd.close()

if name == “main”:
main()

tarena@tedu:~$ python3 01_HttpServer.py

Listen to the port 8000…

浏览器测试:0.0.0.0:8000

IO input output

在内存中存在数据交换的操作都可以认为是输入输出
比如:
内存和磁盘交互 对文件的读写操作
内存和网络交互 recv send

IO密集型程序:程序执行中大量的IO操作,而较少的cpu运算。消耗cpu较少,运行时间长

CPU密集型程序(计算密集型):程序中大量的操作都需要cpu运算,IO操作较少。消耗cpu大,运行速度快

IO 分类
阻塞IO 非阻塞IO IO多路复用 事件IO 异步IO。。

阻塞IO : 默认形态 效率很低的一种IO情形

阻塞情况 :* 因为某种条件没有达成造成的阻塞
e.g. accept recv input

		* 处理IO事件的时候耗时比较长形成阻塞
		e.g.  文件的读写过程,网络数据发送过程

非阻塞IO : 通过修改IO事件的属性,使其变为非阻塞的状态。
(改变了第一种阻塞的状况)

通常和循环搭配使用,不断检测阻塞条件是否已经满足。

s.setblocking()
功能: 将套接字设置为非阻塞状态
参数: bool 设置为False则表示设置为非阻塞

02_block_server.py

from socket import *
from time import sleep,ctime

s = socket()
s.bind((‘127.0.0.1’,9999))
s.listen(5)

#将s设置为非阻塞
s.setblocking(False)

while True:
print(“waiting for connect…”)
try:
connfd,addr = s.accept()
except BlockingIOError:
sleep(2)
print(ctime())
continue

print("Connect from",addr)
#connfd.setblocking(False) #可以将recv设为非阻塞
while True:
    data = connfd.recv(1024).decode()
    if not data:
        break
    print(data)
    connfd.sendall(ctime().encode())
connfd.close()

s.close()

tarena@tedu:~$ python3 02_block_server.py

waiting for connect…

Thu Aug 2 10:42:50 2018

waiting for connect…

Thu Aug 2 10:43:10 2018

waiting for connect…

Thu Aug 2 10:43:12 2018

waiting for connect…

Connect from (‘127.0.0.1’, 58760)

hello

nihao

waiting for connect…

Thu Aug 2 10:43:25 2018

waiting for connect…

Thu Aug 2 10:43:27 2018

waiting for connect…

Connect from (‘127.0.0.1’, 58762)

hello


#tcp_client.py
from socket import *

#创建套接字
sockfd = socket(AF_INET,SOCK_STREAM)

#发起连接 地址:服务端地址
sockfd.connect((‘127.0.0.1’,9999))

while True:
data = input(‘发送>>’)
if not data:
break
#将内容变为bytes格式发送
sockfd.send(data.encode())
data = sockfd.recv(1024).decode()
print(“收到消息:”,data)

sockfd.close()

tarena@tedu:~$ python3 02_tcp_client.py 127.0.0.1 8888

发送>>hello

收到消息: Thu Aug 2 10:43:16 2018

发送>>nihao

收到消息: Thu Aug 2 10:43:20 2018

发送>>

tarena@tedu:~$ python3 02_tcp_client.py 127.0.0.1 8888

发送>>hello

收到消息: Thu Aug 2 10:43:32 2018

发送>>

超时检测

将原本阻塞的函数,设置一个阻塞的最长时间,在规定时间内如果条件
达到则正常执行,如果仍然阻塞则抛出异常

s.settimeout(sec)
功能 : 设置套接字超时时间
参数 : 设置的时间

03_timeout.py

from socket import *
from time import sleep,ctime

s = socket()
s.bind((‘127.0.0.1’,9999))
s.listen(5)

#设置s的超时时间
s.settimeout(5)

while True:
print(“waiting for connect…”)
try:
connfd,addr = s.accept()
except timeout:
sleep(2)
print(ctime())
continue

print("Connect from",addr)
while True:
    data = connfd.recv(1024).decode()
    if not data:
        break
    print(data)
    connfd.sendall(ctime().encode())
connfd.close()

s.close()

IO多路复用

定义 : 同时监控多个IO事件,当哪个IO事件准备就绪就执行哪个IO事件。
以此形成,多个IO事件都可以操作,不必诸个等待执行的效果。

准备就绪:IO事件即将发生的临界状态

import select

select ----》 windows linux unix
poll —》 linux unix
epoll --》 linux unix

In [1]: import select

In [2]: dir(select) # 查看模块下所有包含函数

In [3]: help(select.select) # 查看函数说明文档

r, w, x = select(rlist, wlist, xlist[, timeout])
功能:监控IO事件,阻塞等待IO事件的发生
参数:rlist 列表 存放我们监控等待处理的IO事件
wlist 列表 存放我们要主动处理的IO事件
xlist 列表 存放如果发生异常需要我们处理的
timeout 数字 超时时间
返回值:r 列表 rlist当中准备就绪的IO
w 列表 wlist当中准备就绪的IO
x 列表 xlist当中准备就绪的IO

注意事项 :
1.在处理IO过程中不应该发生死循环(某个IO单独占有服务器)
2.IO多路复用行了一种并发的效果,效率较高

04_select_server.py

from socket import *
from select import select

s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind((“127.0.0.1”,8888))
s.listen(5)

rlist = [s]
wlist = []
xlist = [s]

while True:
#提交关注的IO时间,等待处理
print(“等待IO返回”)
rs,ws,xs = select(rlist,wlist,xlist)
for r in rs:
if r is s:
connfd,addr = r.accept()
print(“Connect from”,addr)
rlist.append(connfd)
else:
data = r.recv(1024)
if not data:
rlist.remove®
r.close()
else:
print(“Receive from”,r.getpeername(),
“:”,data.decode())
#将客户端套接字放到wlist中
wlist.append®
for w in ws:
w.send(“这是一条回复消息”.encode())
wlist.remove(w)

for x in xs:
    if x is s:
        s.close()

练习 : 写一个select服务端 同时关注客户端端的连接,客户端的发送
和终端的输入。将客户端发送的内容和终端输入的内容均写入到
一个文件中

05_write_file.py

from socket import *
from select import select
import sys

s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind((“127.0.0.1”,8888))
s.listen(5)

rlist = [s,sys.stdin]
wlist = []
xlist = []

f = open(‘write_file’,‘w’)

while True:
rs,ws,xs = select(rlist,wlist,xlist)
for r in rs:
if r is s:
c,addr = r.accept()
rlist.append©
elif r is sys.stdin:
data = r.readline()
f.write(data)
else:
data = r.recv(1024)
if not data:
rlist.remove®
else:
f.write(data.decode())

位运算
按照二进制位进行操作运算

&(按位与) |(按位或) ^(按位异或)
<<(左移) >>(右移)

11 1011
14 1110

& 1010 一0则0
| 1111 一1则1
^ 0101 相同为0不同为1
11 << 2 ==> 44 右侧补0
14 >> 2 ==> 3 挤掉低位的数字

使用 : 1. 在做底层硬件的寄存器操作
2. 在做标志位过滤时

poll

  1. 创建poll对象
    p = select.poll()
  2. 添加关注对象
    p.register(s,POLLIN | POLLERR)

p.unregister(s)

poll IO事件类型分类
POLLIN POLLOUT POLLERR POLLHUP POLLPRI POLLVAL
rlist wlist xlist 断开 紧急处理 无效数据

  1. 进行监控
    events = p.poll()
    功能: 阻塞等待register的事件发生
    返回值 : events 是一个列表,列表中每个元素表示准备就绪需要处理的IO
    [(fileno,event),(),()]
    描述符 具体什么就绪了

描述符地图{s.fileno(): s}
4. 处理IO事件

06_poll_server.py

from socket import *
from select import *

s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind((“127.0.0.1”,8888))
s.listen(5)

#创建POLL对象
p = poll()

建立通过fileno查找IO对象的地图

fdmap = {s.fileno()?}
#添加关注
p.register(s,POLLIN | POLLERR)

while True:
#进行监控
events = p.poll()
for fd,event in events:
if fd == s.fileno():
c,addr = fdmap[fd].accept()
print(“Connect from”,addr)
#注册新的套接字
p.register(c,POLLIN)
#维护地图更新
fdmap[c.fileno()] = c
elif event & POLLIN:
data = fdmap[fd].recv(1024)
if not data:
p.unregister(fd)
fdmap[fd].close()
del fdmap[fd]
else:
print(data.decode())
fdmap[fd].send(‘收到了’.encode())

作业 : 1. 熟练 写出 select server代码
2. 能够描述IO多路复用的执行原理和内部机制
3. 巩固HTTPserver的代码—》理解HTTP服务器执行流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值