python TCPsever处理多个连接
转载
- poll解决了套接字有上限的问题,效率和select一样,都是轮询方式。
- 7.单进程tcp服务器 epoll版 (windows不支持)
- epoll-->解决支持上限问题-->采用的是事件通知(效率高)
- 代码
- import select
- from socket import *
- print(dir(select))
- server_socket=socket(AF_INET,SOCK_STREAM)
- server_socket.bind(("",9999))
- server_socket.listen(5)
- epol=epoll() # 创建epoll对象
- epol.register(server_socket.fileno(),EPOLLIN|EPOLLET) # 注册事件
- socket_list={} # 装socket的列表
- socket_addr={} #装socket的地址
- while True:
- print("-------1111111-------")
- epoll_list=epol.poll() # [(fd,事件),(),(),()]
- print("--------22222------")
- for fd,event in epoll_list:
- # 有新的连接
- if fd==server_socket.fileno():
- new_socket,new_addr=server_socket.accept()
- #\往子典中添加数据
- socket_list[new_socket.fileno()]=new_socket
- socket_addr[new_socket.fileno()]=new_addr
- # 注册事件
- epol.register(new_socket.fileno(),EPOLLIN|EPOLLET)
- print("哈哈哈!收到数据了")
- new_socket=socket_list[fd]
- new_addr=socket_addr[fd]
- # 读取数据
- content=new_socket.recv(1024)
- if len(content)>0:
- print("收到数据是:",content.decode("utf-8"))
- epol.unregister(fd) # 取消注册
- new_socket.close()
- print(new_addr,"下线了....")
- 1.没有最大并发连接的限制,能打开的FD(指的是文件描述符,通俗的理解就是套接字对应的数字编号)的上限远大于1024。
- 2.epoll采用的事件通知机制,效率高,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即epoll最大的优点就在于它只管你“活跃”的连接,
- 而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。
- 1.python中fileno() 方法返回一个整型的文件描述符(file descriptor) 打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
- 2.它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,会给这个文件指定一个文件描述符
- 3.习惯上,标准输入sys.stdin.fileno() 的文件描述符为 0 标准输出sys.stdout.fileno() 的文件描述符为 1 标准错误sys.stderr.fileno() 的文件描述符为 2
- 1.进程,线程,协程(微线程)
- 2.协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时。协程,则只使用一个线程,分解一个线程成为多个“微线程”,在一个线程中规定某个代码块的执行顺序。
- 3.协程的应用场景:当程序中存在大量不需要CPU的操作时(IO),线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,
- 4.协程-greenlet-手动切换
- from greenlet import greenlet
- g1=greenlet(协程任务函数名) 创建greennlet对象
- g1.switch() 执行协程并切换
- 使用多个greenlet对象实现多个协程之间的手动切换
- import gevent
- g1=gevent.spawn(协程任务函数名,参数) 创建gevent 对象 并执行
- g1.join() 让线程等待协程执行完毕,否则没机会执行
- 正常开发中,遇到好事操作自动切换协程,(可以在协程中使用gevent.sleep(1)手动搭建耗时操作)
- 也可以使用 gevent.joinall([协程对象1,协程对像2,协程对象n])
- gevent.getcurrent() 返回协程对象
- 并发下载器
- from gevent import monkey
- monkey.patch_all()#猴子补丁,将标准库中涉及的IO操作换成gevent的
- import gevent
- import urllib.request
- #下载地址
- def my_download(url):
- print("GET url==%s" % url)
- result = urllib.request.urlopen(url)
- data = result.read()
- print("url==%s,data is len=%s" % (url,len(data)))
- gevent.spawn(my_download,"https://www.baidu.com"),
- gevent.spawn(my_download,"http://www.atguigu.com"),
- gevent.spawn(my_download,"https://github.com"),
- gevent.spawn(my_download,"http://www.atguigu.com/images/logo.gif"),
- from gevent import monkey,socket,spawn
- monkey.path_all() #把标准库中的socket等给替换掉.
- def server(new_socket):
- content=new_socket.recv(1024)
- if len(content)==0:
- print("收到消息:%s"%content.decode("utf-8"))
- server_socket=socket.socket() #使用gevent中的socket
- server_socket.bind(("",9999))
- server.listen(5)
- while True:
- new_socket,new_addr=server.socket.accept()
- spawn(server,new_socket)
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。