pythonNet day03

TCP应用之 httpserver

  1、接收http请求

  2、查看http请求

  3、返回一个网页给客户端

 1 from socket import *
 2 # 接收请求
 3 # 查看请求
 4 # 返回一个网页给客户端
 5 def handleClient(connfd):    # 处理浏览器发来的请求
 6     request = connfd.recv(4096)
 7     # print("***********")
 8     # print(request)
 9     # print("************")
10     # 按照行切割请求
11     request_lines = request.splitlines()    # 去掉换行符 返回列表
12     for line in request_lines:
13         print(line.decode())
14 
15     try:
16         f = open("index1.html",'r')
17     except IOError:
18         response = "HTTP/1.1 303 Not Found\r\n"
19         request += "\r\n"    # 空行
20         request += """
21         *****************************
22         sorry,not found the page.
23         *****************************
24         """
25     else:
26         response = "HTTP/1.1 200  OK\r\n"
27         response += '\r\n'
28         response += f.read()
29     finally:
30         # 发送给浏览器
31         connfd.send(response.encode())
32 
33 def main(): # 创建套接字,调用handleClient完成功能
34     sockfd = socket()   # 创建TCP套接字
35     sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)    # 设置端口可重用
36     sockfd.bind(("0.0.0.0",8888))
37     sockfd.listen(5)    # 设置为可监听     没有5会怎样
38     while True:
39         print("监听端口8888")
40         connfd,addr = sockfd.accept()   # 等待浏览器连接服务器
41         # 处理浏览器发来的请求
42         handleClient(connfd)    # 处理浏览器发来的请求
43         connfd.close()
44 
45 if __name__ == "__main__":
46     main()
httpserver

在浏览器输入地址:127.0.0.1:8888,即可得到网页显示!

 IO操作

定义:在内存中数据交换的操作被定义为IO操作,IO------输入输出

  内存和磁盘进行数据交换: 文件的读写 数据库更新
  内存和终端数据交换 : input  print
              sys.stdin  sys.stdout   sys.stderr
  内存和网络数据的交换: 网络连接 recv send recvfrom

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

  CPU(计算)密集型程序:程序中存在大量的cpu运算,IO操作相对较少,消耗cpu大。

 IO分类

IO分为:阻塞IO、非阻塞IO、IO多路复用、事件驱动IO、异步IO

阻塞IO : 程序运行中遇到IO条件没有达成或者传输过程较慢的情况会出现阻塞状态

  阻塞IO是IO最简单的逻辑情形,也是默认状态
  阻塞IO是效率很低的IO形态

阻塞情况 :
  因为某种IO条件没有达到形成阻塞
    accept recv recvfrom input

  处理IO事件的时候耗时较长形成阻塞:文件读写过程、网络数据发送过程

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

while True:
print("Waiting for connect...")

try:
c,addr = s.accept()
except BlockingIOError:
time.sleep(2)
print(time.ctime())
continue

print("Connect from",addr)
# c.setblocking(False)
while True:
data = c.recv(1024).decode()
if not data:
break
print(data)
c.close()

s.close()

非阻塞IO : 在程序运行中遇到IO的情形不让其产生阻塞
实现手段: 改变IO事件的属性,使其变为非阻塞  s.setblocking(False)
      通常会和循环一起使用,尽心条件的循环监控
功能 : 将套接字设置为非阻塞
参数 : 默认为阻塞状态 参数设置为False设置为非阻塞IO

超时检测:将原本阻塞的函数,设置一个阻塞的最长时间。在时间内如果仍然阻塞则不再等待
        s.settimeout(sec)
功能 : 设置套接字的超时时间
参数 : 时间 (秒)

from socket import *
import time

s = socket()
s.bind(('127.0.0.1',8888))
s.listen(5)

#设置套接字的超时检测
s.settimeout(3)

while True:
print("Waiting from connect...")
try:
connfd,addr = s.accept()
except timeout:
print("time out....")
continue

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

IO多路复用
定义 通过一个监测,可以同时监控多个IO事件的行为。当哪个IO事件可以执行,即让这个IO事件发生。
IO事件就绪: IO事件即将发生的一个临界状态
      1、在程序中存在的IO事件中选择要监测的
      2、创建监测,将监测的IO事件注册
      3、等待监测的IO时间发生,判断是什么IO事件
      4、处理相应的IO
import select
select ---》 windows linux unix
poll ---》 linux unix
epoll ---》 linux unix
rs, ws, xs = select(rlist, wlist, xlist[, timeout])
功能 : 监控IO事件,阻塞等待监控的IO时间发生
参数 :

  rlist是一个列表,存放我们需要(被动)等待处理的IO (接收)
  wlist是一个列表,存放我们想主动处理的IO(发送)
  xlist是一个列表,存放出错,希望去处理的IO(异常)
  timeout 超时检测
返回值:

  rs是一个列表,rlist中准备就绪的IO
  ws是一个列表,wlist中准备就绪的IO
  xs是一个列表,xlist中准备就绪的IO
* 在处理IO时不要形成死循环,让一个客户端单独占有服务端
* IO多路复兴形成一种可以同时处理多个IO的效果,效率较高

from socket import *
from select import select

s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('0.0.0.0',8888))
s.listen(5)

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

while True:
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)
r.close()
else:
print("Receive:",data.decode())
#讲客户端套接字放入wlist
wlist.append(r)
for w in ws:
w.send("这是一条回复消息".encode())
wlist.remove(w)
for x in xs:
if x is s:
s.close()

位运算:按照二进制位进行运算符操作
  & 按位与   | 按位或   ^ 按位异或    << 左移   >> 右移
  11 1011    14 1110
  (11 & 14    1010)   (11 | 14    1111)   (11 ^ 14    0101 )
  11 << 2 ===> 44 右侧补0    14 >> 2 ===> 3 挤掉右侧的数字
  使用 : 1. 在做底层硬件时操作寄存器
      2. 做标志位的过滤

poll方法实现IO多路复用
  1. 创建poll对象
    p = select.poll()
  2. 注册关注的IO
    p.register(s,POLLIN | POLLERR)
    p.unregister(s) 取消IO关注
  事件类别
    POLLIN POLLOUT POLLERR POLLHUP POLLPRI
    rlist wlist xlist 断开 紧急处理

3. 监控IO
  events = p.poll()
  功能: 监控关注的IO事件
  返回值: 返回发生的IO事件
  events 是一个列表 [(fileno,evnet),(),()....]
  每个就绪IO对应列表中一个元组:(描述符,就绪事件)

  IO地图 : {s.fileno():s}

from socket import *
from select import *

s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('0.0.0.0',8888))
s.listen(5)

#创建poll对象
p = poll()

#创建地图
fdmap = {s.fileno():s}

#添加关注
p.register(s,POLLIN | POLLERR)

while True:
#进行IO监控
#[(fileno,evnet),...]
events = p.poll()
for fd,event in events:
if fd == s.fileno():
#从地图中找到fd对应的对象
c,addr = fdmap[fd].accept()
print("Connect from",addr)
#注册新的IO 维护地图
p.register(c,POLLIN)
fdmap[c.fileno()] = c
else:
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())

4. 处理IO事件

 

猜你喜欢

转载自www.cnblogs.com/LXP-Never/p/9445395.html