python实现select和epoll模型socket网络编程

news/2024/7/9 17:40:27 标签: epoll, python

这里简单搞搞select和eopll的接口开发 ~


select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实

上从现在看来,这也是它所剩不多的优点之一,现在其实更多的人用epoll,在

pythonepoll文档有点少,就先讲究搞搞select ~


select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在

Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一

限制。


说点我的理解,要是用烦了多线程的网络编程,可以试试select的模型。


传递给 select 的参数是几个列表,分别表示读事件、写事件和错误事件。select 方法返回三个列表,其中包含满足条件的对象(读、写和异常)。


服务端的代码:


python">#coding:utf-8
import socket,select
import time
import os
#xiaorui.cc
host = "localhost"
port = 50000
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host,port))
s.listen(5)
while 1:
     infds,outfds,errfds = select.select([s,],[],[],5)
     if len(infds) != 0:
        clientsock,clientaddr = s.accept()
        buf = clientsock.recv(8196)
        if len(buf) != 0:
            print (buf)
            os.popen('sleep 10').read()                                                                                                       
        clientsock.close()
#     print "no data coming"


客户端的代码:


python">#coding:utf-8
import socket,select
#xiaorui.cc
host = "localhost"
port = 50000
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))
                                                                                                                                                                                                                                                                                                                                                                                                                                                    
s.send("coming from select client")
s.close()



170058459.jpg


一个完成的select的例子:

这里有队列的概念

#
import select                                                                                                                                 
import socket
import Queue
import time
import os
#创建socket 套接字
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setblocking(False)
#配置参数
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR  , 1)
server_address= ('192.168.0.101',9999)
server.bind(server_address)
server.listen(10)
inputs = [server]
outputs = []
message_queues = {}
#timeout = 20
while inputs:
    print "waiting for next event"
#    readable , writable , exceptional = select.select(inputs, outputs, inputs, timeout)  最后一个是超时,当前连接要是超过这个时间的话,就会kill
    readable , writable , exceptional = select.select(inputs, outputs, inputs)
                                                                                                                                                       
    # When timeout reached , select return three empty lists
    if not (readable or writable or exceptional) :
        print "Time out ! "
        break;
    for s in readable :
        if s is server:
            #通过inputs查看是否有客户端来
            connection, client_address = s.accept()
            print "    connection from ", client_address
            connection.setblocking(0)
            inputs.append(connection)
            message_queues[connection] = Queue.Queue()
        else:
            data = s.recv(1024)
            if data :
                print " received " , data , "from ",s.getpeername()
                message_queues[s].put(data)
                # Add output channel for response
                if s not in outputs:
                    outputs.append(s)
            else:
                #Interpret empty result as closed connection
                print "  closing", client_address
                if s in outputs :
                    outputs.remove(s)
                inputs.remove(s)
                s.close()
                #清除队列信息
                del message_queues[s]
    for s in writable:
        try:
            next_msg = message_queues[s].get_nowait()
        except Queue.Empty:
            print " " , s.getpeername() , 'queue empty'
            outputs.remove(s)
        else:
            print " sending " , next_msg , " to ", s.getpeername()
            os.popen('sleep 5').read()
            s.send(next_msg)
                                                                                                                                                           
    for s in exceptional:
        print " exception condition on ", s.getpeername()
        #stop listening for input on the connection
        inputs.remove(s)
        if s in outputs:
            outputs.remove(s)
        s.close()
        #清除队列信息
        del message_queues[s]


关于epoll的方面,大家可以看看这个老外的文档,写不错 ~


select是轮询、epoll是触发式的,所以epoll的效率高。


参考的文档地址:http://scotdoyle.com/python-epoll-howto.html


下面是用epoll实现一个服务端 ~


blog from xiaorui.cc


import socket, select
EOL1 = b'\n\n'
EOL2 = b'\n\r\n'
response  = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'
response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n'
response += b'Hello, world!'
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.bind(('0.0.0.0', 8080))
serversocket.listen(1)
serversocket.setblocking(0)
epoll = select.epoll()
epoll.register(serversocket.fileno(), select.EPOLLIN)
try:
   connections = {}; requests = {}; responses = {}
   while True:
      events = epoll.poll(1)
      for fileno, event in events:
         if fileno == serversocket.fileno():
            connection, address = serversocket.accept()
            connection.setblocking(0)
            epoll.register(connection.fileno(), select.EPOLLIN)
            connections[connection.fileno()] = connection
            requests[connection.fileno()] = b''
            responses[connection.fileno()] = response
         elif event & select.EPOLLIN:
            requests[fileno] += connections[fileno].recv(1024)
            if EOL1 in requests[fileno] or EOL2 in requests[fileno]:
               epoll.modify(fileno, select.EPOLLOUT)
               connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1)
               print('-'*40 + '\n' + requests[fileno].decode()[:-2])
         elif event & select.EPOLLOUT:
            byteswritten = connections[fileno].send(responses[fileno])
            responses[fileno] = responses[fileno][byteswritten:]
            if len(responses[fileno]) == 0:
               connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 0)
               epoll.modify(fileno, 0)
               connections[fileno].shutdown(socket.SHUT_RDWR)
         elif event & select.EPOLLHUP:
            epoll.unregister(fileno)
            connections[fileno].close()
            del connections[fileno]
finally:
   epoll.unregister(serversocket.fileno())



Epoll的最大好处是不会随着FD的数目增长而降低效率,在select中采用轮询处理,每个fd的处理情况,而epoll是维护一个队列,直接看队列是不是空就可以了。


在这里也推荐大家用epoll写服务端的东西,当然我自己理解的不够好,咱们多交流 !!!





http://www.niftyadmin.cn/n/1673789.html

相关文章

介绍理想工作计算机 英语作文,成为一名电脑工程师是我的理想 To Be a Computer Expert Is My Ideal...

To Be a Computer Expert Is My Ideal-我的理想是当一名电脑专家上小学的时候,家里买了电脑,我对它迷恋极了。从此我有了一个理想,即当一名电脑专家。我要用自己的智慧和勤奋发明世界上最先进的电脑。我相信只要我努力学习,理想就…

基于linux的qt五子棋小游戏下载,课内资源 - 基于Qt的图形化界面网络在线对战五子棋游戏...

一 需求分析本软件是一款跨平台的网络实时五子棋对战软件,实现建立主机和连接主机、实时对战、判断输赢和危险提示等功能。支持Windows 、 Linux和OSX平台。程序主要功能如下:建立服务器能创建网络主机。在界面上添加功能按钮,显示创建主机对…

在论坛中出现的比较难的sql问题:18(字符合并1)

最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了。 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也…

linux 找不到su,ubuntu12.04下使用su,vi等命令时,提示找不到命令

在我们安装一些软件的时候,为了方便使用,比如jre等,可能需要设置一些环境变量。但是在设置环境变量时,要非常小心,由于我是新手,对环境变量的设置不太熟悉,在设置PATH环境变量时,将环…

麦吉尔学和ubc计算机专业,UBC大学—电子计算机工程专业

UBC大学—电子计算机工程专业世界级顶尖研究型大学,它庞大而又秀丽,坐落于风光如画的温哥华市,同时它也是加拿大最难申请的大学以及淘汰率最高的大学之一。UBC于1908年由麦吉尔大学合作创校,主要有两个校区,温哥华校区…

【转载】计算汉字相似程度

package com.thunisoft.in4.cm.associate.util;import java.util.List; import java.util.Map;/*** 编辑距离算法* * author fanxf* */ public class HanziParse {/*** 计算矢量距离 Levenshtein Distance(LD)* * param str1* str1* param str2* str2* r…

gcc4.6 linux安装包,CentOS 5.5 手动安装 GCC4.6.2

从GCC官网下载最新版本的GCC4.6.2http://gcc.gnu.org/国内镜像地址:http://mirrors.ustc.edu.cn/gnu/gcc/首先在配置gcc的过程中会出现错误:# ./configure --prefix/usr/local/gcc-4.6.2configure: error: Building GCC requires GMP 4.2, MPFR 2.3.1 an…

用计算机求函数公式,计算机常用函数公式

大家好,我是时间财富网智能客服时间君,上述问题将由我为大家进行解答。计算机常用函数公式主要有:SUM函数、ABS函数、AND函数、AVERAGE函数、IF函数、COUNTIF函数、RANK函数等。电子计算机(electronic computer)通称电脑,是现代一…