网络编程2

HTTP请求: request

  • 请求格式:
  • 1、请求行         GET (请求种类)             / (请求内容)              HTTP/1.1(协议版本)
  •               请求种类 
  • GET        获取网络资源
  • POST     提交一定的附加数据,得到返回结果。
  • HEAD     获取响应头
  • PUT        更新服务器资源
  • DELETE  删除服务器资源
  • CONNECT 预留
  • TRACE     测试
  • OPTIONS  获取服务器性能
  • 2、请求头   对请求内容的具体描述,系统会自动填充。
  •      以键值对的形式对请求信息进行描述
  •      Accept-Language:zh-CN,zh;q=0.9
  • 3、空行
  • 4、请求体  提交具体的请求参数

 

 

 

HTTP响应:Response

响应格式:

响应行   反馈具体的相应情况

        HTTP/1.1       200               OK

        版本信息        响应码         附加信息

        响应码: 1xx        提示信息  表示请求已经接受

                       2xx         相应成功

                        3xx         响应需要重新请定向

                        4xx         客户端错误

                         5xx        服务器错误

        常见响应码: 200  成功   404 请求页面不存在    401  没有访问权限   500  服务器发生位置错误 503 服务器暂时无法执行

响应头   对相应信息的具体描述

        eg:Cache-Control :private

空行

响应体    将客户想要的内容进行返回

      

基础的http服务流程程序:

1、接受http请求

2、给出一定的响应

from socket import *

#处理请求,返回响应
def handleClient(connfd):
    print("Connect from",connfd.getpeername())
    request = connfd.recv(4096)
    print(request)
    #进行分行
    requestHeadLers = request.splitlines()
    for i in requestHeadLers:
        print(i)
    #无论什么请求给出响应的响应。
    try:    
        print("========")
        f = open("index.html")
    except IOError:
        response = "HTTP/1.1 404 not found\r\n"
        response += '\r\n'
        response += '==Sorry,The page not foundsdfa=='
    else:
        response = 'HTTP/1.1 200 OK\r\n'
        response += '\r\n'
        for i in f:
            response += i
    finally:
        connfd.send(response.encode())
    connfd.close()
#网络连接控制流程
def main():
    print("进入")
    sockfd = socket()
    sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    sockfd.bind(("0.0.0.0",8000))
    sockfd.listen(5)
    print("---")
    while True:
        print("Listen to the port 80000...")
        connfd,addr = sockfd.accept()
        handleClient(connfd)
    
if __name__ == "__main__":
    main()
    

IO: input output

凡是在内存中存在数据交换的操作都可以认为是IO操作

比如:内存和磁盘交互   读写read write

           内存和终端交互  print  input

           内存和网路交互 recv send

 

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

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

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

 

阻塞IO:默认形态   效率很低的一种IO,简单。

阻塞情况: * 因为某种条件没有达到造成的阻塞。 eg:input  accept  recv

                   * 处理IO事件的时间消耗较长带来阻塞   eg:文件的读写过程,网络数据发送过程

非阻塞IO: * 通过修改IO事件的属性,使其变为非阻塞状态,即避免条件阻塞的情况

                   *非阻塞IO往往和循环搭配使用,这样可以不断执行部分需要执行的代码,也不影响对阻塞条件的判断。

            

设置套接字为非阻塞:

s.setblocking()

功能:设置套接字的阻塞状态

参数:设置为False则套接字调用函数为非阻塞。

 #非阻塞程序
from socket import  *
from time import sleep,ctime

s = socket()
s.bind(('127.0.0.1',8888))
s.listen(5)
#设置s为非阻塞
s.setblocking(False)
#recv变成非阻塞的方法
#connfd.setblocking(False)
while True: 
    print("Waiting for connect...")
    try:
        connfd,addr = s.accept()
    except BlockingIOError:
        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设置一个最长阻塞等待事件,在规定事件内如果达到条件则正常执行,如果事件到仍未达到条件则结束阻塞。

s.settimeout(sec)

功能:设置套接字超时时间

参数:设置的时间

 #超时等待 settimeout(5)
from socket import  *
from time import sleep,ctime

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

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

while True: 
    print("Waiting for connect...")
    try:
        connfd,addr = s.accept()
    except timeout:
        print("time out")
        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

 

rlist,wlist,xlist = select(rlist,wlist,xlist[,timeout])

功能:监控IO事件,阻塞等待IO事件发生。

参数:rlist   列表 要监控的读IO事件   存放被动等待处理的IO事件

         wlist 列表  要监听的写 IO 事件  存放需要主动处理的IO

         xlist  列表  要监控的出错IO事件 存入如果发生异常需要处理的IO

         timeout  超时时间

返回值:   rlist   列表   rlist中准备就绪的IO

                wlist  列表   wlist中准备就绪的IO

                xlist   列表   xlist中准备就绪的IO

 

注意事项:

1、IO多路复用处理IO的过程中不应有死循环出席那,使一个客户端长期占有服务端。

2、IO多路复用是一种并发行为,但是是单进程程序,效率较高。

from socket import *
from select import select

s = socket()

#创建tcp套接字作为关注的IO
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(("127.0.0.1",8888))
s.listen(5)

#三个关注列表
rlist = [s]
wlist = []
xlist = []

while True:
    print("waitting for .....")
    rs,ws,xs = select(rlist,wlist,xlist)
    
    print("Connect from")
    
    for r in rs:
        if r is s:
            connfd,addr = r.accept()
            print("Connect from",connfd)
            #增加关注事件
            rlist.append(connfd)
        else:
            data = r.recv(1024).decode()
            if not data:
                rlist.remove(r)
                r.close()
            else:
                print("receive:",data)
                wlist.append(r)
                #r.send(b"Receive your message")
    for w in ws:
        w.send("这是一条回复消息".encode())
    #处理异常IO
    for x in xs:
        if x is s:
            s.close()
            sys.exit(0)

f = open()

f.flush() 清空缓冲区。

import select
import socket
import sys

sockfd = socket.socket()

sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
sockfd.bind(("0.0.0.0",8888))
sockfd.listen(5)

#三个关注列表
rlist = [sockfd,sys.stdin]
wlist = []
xlist = []

f = open("test.txt","w")

while True:
    #提交关注的IO事件,等待处理
    print("Waiting for IO")
    rs,ws,xs = select(rlist,wlist,xlist)
    for r in rs:
        if r is rs:
            c,addr = r.accept()
            rlist.append(c)
        elif r is sys.stdin:
            data = r.readline()
            f.write(data)
        else:
            data = r.recv(1024)
            if not data:
                rlist.remove(r)
            else:
                f.write(data.decode()+"\n")

poll(IO多路复用)

from select import poll 

1、创建poll对象

p = poll()

2、添加关注的IO

poll  IO事件分类

POLLIN   POLLOUT   POLLERR POLHUP  POLLDRI  POLLVAL

rlist           wlist            xlist            断开连接   紧急处理   无效

p.register(s,POLLIN | POLLERR)  关注io

p.unregister(s)   取消对IO的关注

3、进行监控

events = p.poll()

功能:监控关注的IO,阻塞等待IO发生。

返回值:events是一个列表,列表中每个元素为一个元组,代表准备就绪需要处理的IO

events --》[(      fileno,           event),(),()]

                   就绪IO的fileno   哪个事件就绪

因为要获取IO对象调用函数 ---》通过fileno得到对象

实施方法:建立比照字典 {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 = pull()

#建立通过fileno查找IO对象的字典
fdmap = {s.fileno():s}

#注册关注IO事件
p.register(s,PULLIN|POLLERR)

while True:
    #监控关注的IO
    events = p.poll()
    
    for fd,event in events:
        if fd == s.fileno():
            c,addr = fdmap[fd].accept()
            print("Connect from",addr)
            #注册新的关注IO
            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())
    
    
    
    
    

4、处理IO

epoll  方法:

使用方法: 与poll基本相同

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) 

#创建epoll对象
p = epull()

#建立通过fileno查找IO对象的字典
fdmap = {s.fileno():s}

#注册关注IO事件
p.register(s,EPULLIN|EPOLLERR)

while True:
    #监控关注的IO
    events = p.poll()
    
    for fd,event in events:
        if fd == s.fileno():
            c,addr = fdmap[fd].accept()
            print("Connect from",addr)
            #注册新的关注IO
            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())
    
    
    
    
    

注意:生成对象使用epoll() 而不是poll()

           register注册IO事件事件类型改为EPOLL事件类型。

 

select  poll epoll区别

1、select可以很好支持windows

2、epoll比select和poll效率高,select和poll差不多

3、epoll提供了更多的触发方式

 

 

本地套接字:

 

linux下文件类型:

b  块是设备文件

c  字符设备文件

d  目录

- 普通文件

l 连接

s 套接字

p 管道

 

s 作用:用于本地不同程序间进行通信。开辟一个内存,两个程序通过内训通信。

本地套接字创建流程:
1、创建套接字对象

sockfd = socket(AF_UNIX,SOCK_STREAM)

2、绑定本地套接字文件

sockfd.bind(path)

path:一个文件

3、监听

4、接受发送消息

 

os.path.exists(path)

功能:判断一个文件夹下是否有某个文件

返回值: True   False

 

os.unlink(path)  os.remove(path)

功能:删除一个文件

from socket import * 
import os

#linux下:使用哪个文件作为套接字文件
sock_file = "./sock"

#判断文件是否已经存在
if os.path.exists(sock_file):
    os.unlink(sock_file)
    
#创建本体套接字
sockfd = socket(AF_UNIX,SOCK_STREAM)

#绑定
sockfd.bind(sock_file)

#监听
sockfd.listen(5)

while True:
    c,addr = sockfd.accept()
    while True:
        data = c.recv(1024)
        if not data:
            break
        print(data.decode())
    c.close()
sockfd.close()
        



from socket import *

#确保通信两端用相同的套接字文件
sock_file = "./sock"

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

#连接
sockfd.connect(sock_file)

while True:
    msg = input("Msg>>")
    if msg:
        sockfd.send(msg.encode())
    else:
        break
sockfd.close()

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值