python 實現一個epoll
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 = 5
#建立epoll事件對象,後續要監控的事件添加到其中
epoll = select.epoll()
#註冊服務器監聽fd到等待讀事件集合
epoll.register(serversocket.fileno(), select.EPOLLIN)
#保存鏈接客戶端消息的字典,格式爲{}
message_queues = {}
#文件句柄到所對應對象的字典,格式爲{句柄:對象}
fd_to_socket = {serversocket.fileno():serversocket,}
while True:
print "等待活動鏈接......"
#輪詢註冊的事件集合,返回值爲[(文件句柄,對應的事件),(...),....]
events = epoll.poll(timeout)
if not events:
print "epoll超時無活動鏈接,從新輪詢......"
continue
print "有" , len(events), "個新事件,開始處理......"
for fd, event in events:
socket = fd_to_socket[fd]
#若是活動socket爲當前服務器socket,表示有新鏈接
if socket == serversocket:
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] = 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 data:
print "收到數據:" , data , "客戶端:" , socket.getpeername()
#將數據放入對應客戶端的字典
message_queues[socket].put(data)
#修改讀取到消息的鏈接到等待寫事件集合(即對應客戶端收到消息後,再將其fd修改並加入寫事件集合)
epoll.modify(fd, select.EPOLLOUT)
#可寫事件
elif event & select.EPOLLOUT:
try:
#從字典中獲取對應客戶端的信息
msg = message_queues[socket].get_nowait()
except Queue.Empty:
print socket.getpeername() , " queue empty"
#修改文件句柄爲讀事件
epoll.modify(fd, select.EPOLLIN)
else :
print "發送數據:" , data , "客戶端:" , socket.getpeername()
#發送數據
socket.send(msg)
#在epoll中註銷服務端文件句柄
epoll.unregister(serversocket.fileno())
#關閉epoll
epoll.close()
#關閉服務器socket
serversocket.close()
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)
while True:
#輸入數據
data = raw_input('please input:')
#客戶端發送數據
clientsocket.sendall(data)
#客戶端接收數據
server_data = clientsocket.recv(1024)
print '客戶端收到的數據:%s' % server_data
#關閉客戶端socket