# coding=utf-8
import socket, logging
import select, errno
if __name__ == "__main__":
try:
# 创建TCP服务器
listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
except socket.error, msg:
logging.error("create a socket failed")
try:
# 设置SO_REUSEADDR参数 保证socket断开时其占用的端口可以立刻被重用
listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except socket.error, msg:
logging.error("setsocketopt error")
try:
listen_fd.bind(('localhost', 9999))
except socket.error, msg:
logging.error("listen file id bind ip error")
try:
# 设置监听的文件描述符的监听数量
listen_fd.listen(10)
except socket.error, msg:
logging.error(msg)
try:
epoll_fd = select.epoll()
# 注册读事件。 当有新的客户端请求连接时 会触发这个事件
epoll_fd.register(listen_fd.fileno(), select.EPOLLIN)
except select.error, msg:
logging.error(msg)
connections = {}
datamap = {}
while True:
events = epoll_fd.poll()
for fd, event in events: # fd:文件描述符 event:就绪事件
if fd == listen_fd.fileno():
# 如果有新的socket请求连接
conn, addr = listen_fd.accept()
# 请求阻塞模式
conn.setblocking(0)
# 注册读事件
epoll_fd.register(conn.fileno(), select.EPOLLIN | select.EPOLLET)
connections[conn.fileno()] = conn
elif select.EPOLLIN & events:
# 有读事件发生 我们可以从客户端读取数据
datas = ''
while True:
try:
# 我们每次就去读取20个
data = connections[fd].recv(20)
if not data and not datas:
# 没有读取到数据 并且之前的累计数据也没有
epoll_fd.unregister(fd)
connections[fd].close()
break
else:
datas += data
except socket.error, msg:
# ET模式下 返回EAGAIN表示数据读取完了。
if msg.errno == errno.EAGAIN:
datamap[fd] = datas
# 给文件描述符监听可写事件
epoll_fd.modify(fd, select.EPOLLET | select.EPOLLOUT)
break
else:
epoll_fd.unregister(fd)
connections[fd].close()
logger.error(msg)
break
elif select.EPOLLHUP & events:
# 有HUP事件激活
epoll_fd.unregister(fd)
connections[fd].close()
elif select.EPOLLOUT & events:
# 将buffer中的数据写到客户端中
sendLen = 0
while True:
sendLen += connections[fd].send(datamap[fd][sendLen:])
if sendLen == len(datamap[fd]):
break
# 设置监听事件为读取 这样的话又可以接受客户端发来的数据
epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLET)
else:
continue
0I Like It!
网友评论