网络编程6(IO模型)

IO  sock对象本质是文件描述符,什么是文件描述符,是一个非零的整数,内核区接受的数据,在用户拷贝完以后就没有了html

IO多路复用比阻塞IO的好处是能够监听多个sock对象,能处理多个链接,IO多路复用全程阻塞,能实现并发现象,必定不是同时聊,没有开多线程多进程web

什么是阻塞IO,(什么是非阻塞IO),主进程会一直卡住不能干其余事,知道对应的操做结束,非阻塞IO不会卡,缓存

阻塞IO全程阻塞,非阻塞IO,copydaty时进程阻塞,IO多路复用全程阻塞;这三个是同步IO模型,只有第四个异步IO全程无阻塞,可是实现麻烦,全程由操做系统完成(waitdata copydata)网络

 同步IO只要两个过程(wait data,copy data)有一个是阻塞的就叫同步IO多线程

同步:  阻塞IO  非阻塞IO  io多路复用(select epoll poll)
异步:  异步IO

IO模型有几个角色: 进程,操做系统(内核),IO都是进程的Io并发

http://www.cnblogs.com/yuanchenqi/articles/6755717.htmlapp

IO模型
进程若是有数据的交换,进程发系统调用进入内核态,内核态的数据cp到用户空间,分两个过程,wait for data ,copy data


阻塞IO




非阻塞IO

 IO多路复用异步

 


 IO multiplexing这个词可能有点陌生,可是若是我说select,epoll,大概就都能明白了。有些地方也称这种IO方式为event driven IO。咱们都知道,select/epoll的好处就在于单个process就能够同时处理多个网络链接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的全部socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:

 

   当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”全部select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操做,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并无太大的不一样,事实上,还更差一些。由于这里须要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。可是,用select的优点在于它能够同时处理多个connection。(多说一句。因此,若是处理的链接数不是很高的话,使用select/epoll的web server不必定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优点并非对于单个链接能处理得更快,而是在于能处理更多的链接。)
在IO multiplexing Model中,实际中,对于每个socket,通常都设置成为non-blocking,可是,如上图所示,整个用户的process实际上是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。socket

 

结论: select的优点在于能够处理多个链接,不适用于单个链接 函数

 

 

 

 

总结##################################################################################

IO就是进程有须要数据的时候才会产生IO系统调用,分两个阶段 1:wait for data;2: copy data

阻塞IO全程阻塞(进程在须要IO调用的时候,用户程序发动系统调用,从用户态转到内核态(内核态是操做系统管理,有操做硬件的权限)直到数据从内核缓存区cp到用户区,此时内核的数据直接清除),

非阻塞IO wait for data不阻塞,用户程序会隔一段时间就到内核区问问,数据准备好了没有,一次次的发起系统调用,直到有数据了,阻塞cp数据

IO多路复用:这个最大的改善是用户程序调用select函数发起系统调用阻塞等数据,等数据到了,用户进程发起系统调用cp数据,而后清除内核缓存中的数据,比IO阻塞多了个系统调用,下面的例子多个客户端聊天
就是及于此
1 阻塞IO: 全程阻塞 2 非阻塞IO:
优势:wait
for data时无阻塞 缺点:1 系统调用太多 2 数据不是实时接受的 两个阶段:wait for data:非阻塞 copy data :阻塞 3 IO多路复用(监听多个链接)
sock::sock <socket.socket fd=224, 
family=AddressFamily.AF_INET, 
type=SocketKind.SOCK_STREAM, 
proto=0, laddr=('127.0.0.1', 8800)>
224就是文件打桩符
对于文件描述符(套接字对象):
1 是一个非零整数,不会变
2 收发数据的时候,对于接收端而言,数据先到内核空间,
而后copy到用户空间,同时,内核空间数据清除。

特色:1 全程(wait for data,copy)阻塞
      2 能监听多个文件描述符
      
      实现并发
       
4 异步IO

  全程无阻塞,


5 驱动信号

总结: 
同步:  阻塞IO  非阻塞IO  io多路复用
异步:  异步IO

 

#server端
#简单聊天,最大接受5个client排队,第一个链接后就进入while第二个,阻塞socket模块

import socket
import time

sock=socket.socket()

sock.bind(("127.0.0.1",8800))

sock.listen(5)

#sock.setblocking(False)

# while 1:
#     try:
#         conn,addr=sock.accept()   # 阻塞等待连接
#     except Exception as e:
#         print(e)
#         time.sleep(3)

# data=conn.recv(1024)
#
# print(data.decode("utf8"))

while 1:
    conn,addr=sock.accept()
    print("server working.......")
    while 1:

        data=conn.recv(1024)
        print(data.decode("utf8"))
        send_data=input(">>>")
        conn.send(send_data.encode("utf8"))

    conn.close()







#client端



import socket

sock=socket.socket()


sock.connect(("127.0.0.1",8800))

while 1:

     data=input("input>>>")
     sock.send(data.encode("utf8"))
     rece_data=sock.recv(1024)
     print(rece_data.decode("utf8"))

sock.close()

 

 

 

#给予select机制实现多客户端并发聊天   若是几个客户端前后发消息过来,监控的列表中conn几个会有变化,server端会吧有变化的conn for遍历一遍回消息再

#server端

#sock是客户来链接才有变化,conn是客户发消息才有变化,主要仍是解决IO操做



import socket
import time

import select
sock=socket.socket()

sock.bind(("127.0.0.1",8800))

sock.listen(5)


sock.setblocking(False)
inputs=[sock,]

print("sock",sock)

while 1:
    r,w,e=select.select(inputs,[],[])  # select只监听有变化的套接字 inputs=[sock,conn1,conn2,conn3..] #开启select首先到这,
    print("r",r)
    for obj in r:   # 第一次 [sock,]  第二次(客户端发消息) #[conn1,]
        if obj==sock:#客户端第一次链接走这条路
            print('change')
            conn,addr=obj.accept()
            inputs.append(conn)   #  inputs=[sock,conn]

        else:#客户端第二次发消息走这条路
            data=obj.recv(1024)
            print(data.decode("utf8"))
            send_data=input(">>>")
            obj.send(send_data.encode("utf8"))




#client 端
#跟上面的同样
相关文章
相关标签/搜索