python epoll

 

1、server

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import socket
import select
import Queue

#创建socket对象
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#设置IP地址复用
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#ip地址和端口号
server_address = ("127.0.0.1", 8888)
#绑定IP地址
serversocket.bind(server_address)
#监听,并设置最大连接数
serversocket.listen(10)
print  "服务器启动成功,监听IP:" , server_address
#服务端设置非阻塞
serversocket.setblocking(False)  
#超时时间
timeout = 10
#创建epoll事件对象,后续要监控的事件添加到其中
epoll = select.epoll()
#注册服务器监听fd到等待读事件集合
epoll.register(serversocket.fileno(), select.EPOLLIN)
#保存连接客户端消息的字典,格式为{}
message_queues = {}
#文件句柄到所对应对象的字典,格式为{句柄:对象}
fd_to_socket = {}
fd_to_socket[serversocket.fileno()] = serversocket

print "serversocket: ", serversocket.fileno()
print "EPOLLIN: ", select.EPOLLIN
print "EPOLLOUT: ", select.EPOLLOUT
print "EPOLLHUP: ", select.EPOLLHUP
print "EPOLLIN: ", select.EPOLLIN


while True:
    print "等待活动连接......"
    #轮询注册的事件集合,返回值为[(文件句柄,对应的事件),(...),....]
    events = epoll.poll(timeout)
    if not events:
        print "epoll超时无活动连接,重新轮询......"
        continue
    print "有" , len(events), "个新事件,开始处理......"
 
    for fd, event in events:
        print "fd, event: ", fd, event

        socket = fd_to_socket[fd]
        #如果活动socket为当前服务器socket,表示有新连接
        if fd == serversocket.fileno():
            connection, address = serversocket.accept()
            print "新连接:" , address
            #新连接socket设置为非阻塞
            connection.setblocking(False)
            #注册新连接fd到待读事件集合
            epoll.register(connection.fileno(), select.EPOLLIN)
            #把新连接的文件句柄以及对象保存到字典
            fd_to_socket[connection.fileno()] = connection
            #以新连接的对象为键值,值存储在队列中,保存每个连接的信息
            message_queues[connection.fileno()] = Queue.Queue()
        #关闭事件
        elif event & select.EPOLLHUP:
            print 'client close'
            #在epoll中注销客户端的文件句柄
            epoll.unregister(fd)
            #关闭客户端的文件句柄
            fd_to_socket[fd].close()
            #在字典中删除与已关闭客户端相关的信息
            del fd_to_socket[fd]
        #可读事件
        elif event & select.EPOLLIN:
            #接收数据
            data = socket.recv(1024)
            if len(data) == 0:
                # 触发读事件,而数据长度为0,则默认客户端关闭连接
                print "client close fd: ", fd
                epoll.unregister(fd)
                #关闭客户端的文件句柄
                fd_to_socket.pop(fd).close()
                del message_queues[fd]
            else:
                print "收到数据:" , data , "客户端:" , socket.getpeername()
                #将数据放入对应客户端的字典
                print "queue put data ", message_queues, fd
                message_queues[fd].put(data)
                print "message_queues: ", message_queues[fd]
                #修改读取到消息的连接到等待写事件集合(即对应客户端收到消息后,再将其fd修改并加入写事件集合)
                if data[-1] == 'n':
                    epoll.modify(fd, select.EPOLLOUT)
                
        #可写事件
        elif event & select.EPOLLOUT:
            try:
                #从字典中获取对应客户端的信息
                send_msg = ''
                while True:
                    msg = message_queues[fd].get_nowait()
                    send_msg = msg + send_msg
                    if msg[-1] == 'n':
                        break
            except Queue.Empty:
                print socket.getpeername() , " queue empty"
                #修改文件句柄为读事件
                epoll.modify(fd, select.EPOLLIN)
            else :
                print "发送数据:" , send_msg , "客户端:" , socket.getpeername()
                #发送数据
                socket.send(send_msg)

#在epoll中注销服务端文件句柄
epoll.unregister(serversocket.fileno())
#关闭epoll
epoll.close()
#关闭服务器socket
serversocket.close()

2、client

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import socket

#创建客户端socket对象
clientsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#服务端IP地址和端口号元组
server_address = ('127.0.0.1',8888)
#客户端连接指定的IP地址和端口号
clientsocket.connect(server_address)

print "clientsocket fd: ", clientsocket.fileno()

while True:
    #输入数据
    data = raw_input('please input:')
    if data == 'k':
        break
    clientsocket.sendall(data)
    if data[-1] != 'n':
        #客户端发送数据
        continue
    #客户端接收数据
    server_data = clientsocket.recv(1024)
    print '客户端收到的数据:', server_data
    #关闭客户端socket
clientsocket.close()

 

注意server代码可能有问题,就是在client端断开连接时,server端fd触发的事件可能是1,也就是EPOLLIN,而不是EPOLLHUP,从而导致server读取数据时为空,这部分我用了逻辑判断读取数据长度为0时,客户端断开,关闭fd。

另外,客户端输入k标识中断连接;输入数据结尾加n标识输入结束;服务端同样在识别到接收数据结尾为n是才判断客户端消息发送结束;

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值