# -*- coding: utf-8 -*-
# !/usr/bin/env python
###################################################
# Teaching Wisedom to My Computer,
# Please Call Me Croco,Fuck Your Foolishness.
##################################################
import sys
import socket
import select
import os
import traceback
import copy
import errno
import signal
import threading
isContinue_event = threading.Event()
is_sigint_up = False
def sigint_handler(signum, frame):
global is_sigint_up
global isContinue_event
is_sigint_up = True
isContinue_event.set()
# print 'sigint_handler,catched interrupt signal!'
'''
class ServerInterface
定义一个Server的通用接口,被InterruptableTaskLoop调用
'''
class ServerInterface(object):
# ServerInterface.start()
def start(self):
raise NotImplementedError()
# ServerInterface.stop()
def stop(self):
raise NotImplementedError()
# ServerInterface.serve_once()
def serve_once(self):
raise NotImplementedError()
# ServerInterface.notify()
def notify(self, message):
raise NotImplementedError()
#
# The `InterruptableTaskLoop` Class
#
class InterruptableTaskLoop(object):
def __init__(self, worker, timeout=1):
'''
:param worker: requre methods is :start() serve_once() stop() notify()
:param timeout:
'''
if not hasattr(worker, 'start'):
raise AttributeError("AttributeError:miss method called start() ")
if not hasattr(worker, 'serve_once'):
raise AttributeError("AttributeError:miss method called serve_once() ")
if not hasattr(worker, 'stop'):
raise AttributeError("AttributeError:miss method called stop() ")
if not hasattr(worker, 'notify'):
raise AttributeError("AttributeError:miss method called notify() ")
self.worker = worker
self.timeout = timeout
pass
def wait(self):
'''
:return:
'''
try:
isContinue_event.clear()
isContinue_event.wait(timeout=self.timeout)
except:
pass
def startAsForver(self):
'''
:return:
'''
global is_sigint_up
global isContinue_event
is_sigint_up = False
signal.signal(signal.SIGINT, sigint_handler)
isOK = self.worker.start()
if not isOK:
self.worker.notify("self.worker.start failed ,then system.exit")
return
while not is_sigint_up:
try:
self.wait()
self.worker.serve_once()
except Exception, e:
message = "caught a exception in func>serve_once,message is:{0}".format(e.message)
self.worker.notify(message)
else:
self.worker.notify("self.worker.stop,catched interrupt signal")
self.worker.stop()
#################################################################
class EchoServer(ServerInterface):
def __init__(self, listen_port):
self._listen_port = listen_port
self._listen_addr = ("0.0.0.0", self._listen_port)
self._listen_backlog = 128
self._time_out = 0.01
pass
# ServerInterface.start()
def start(self):
self._listen_socket_list = []
self._acceptor_dict = {}
self._session_id = 0
self._is_started = 0
try:
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.setblocking(False)
listen_socket.bind(self._listen_addr)
listen_socket.listen(self._listen_backlog)
self._listen_socket_list.append(listen_socket)
print "EchoServer::Start() listen in port:{0} pid:{1}".format(self._listen_addr,os.getpid())
self._is_started = 1
return True
except:
(ErrorType, ErrorValue, ErrorTB) = sys.exc_info()
info = "listen failed:{0} {1} ".format(ErrorValue, self._listen_addr)
print info
self._is_started = 0
return False
# ServerInterface.stop()
def stop(self):
print "ServerInterface.stop()"
for listen_socket in self._listen_socket_list:
if listen_socket:
listen_socket.close()
self._listen_socket_list = []
for acceptor in self._acceptor_dict.values():
acceptor.onDisconnectEvent()
self._acceptor_dict.clear()
self._is_started = 0
def _assignSessionId(self):
self._session_id += 1
return self._session_id
def _addTcpAcceptor(self, acceptor):
self._acceptor_dict[acceptor.client_socket] = acceptor
print "_addTcpAcceptor sessionId:{0} fd:{1} addr:{2}".format(acceptor.client_session_id,
acceptor.client_socket.fileno(),
acceptor.client_addr)
def _delTcpAcceptor(self, acceptor):
if acceptor.client_socket in self._acceptor_dict:
self._acceptor_dict[acceptor.client_socket]
print "_delTcpAcceptor sessionId:{0} fd:{1} addr:{2}".format(acceptor.client_session_id,
acceptor.client_socket.fileno(),
acceptor.client_addr)
del self._acceptor_dict[acceptor.client_socket]
return
print "_delTcpAcceptor nothing"
def _onFdAccept(self, listen_socket):
client_socket, client_address = listen_socket.accept()
#client_socket.setblocking(False)
acceptor = _Acceptor(self._assignSessionId(), client_socket, client_address, client_status=1)
self._addTcpAcceptor(acceptor)
def _onFdRead(self, client_socket):
acceptor = self._acceptor_dict.get(client_socket, None)
if acceptor is None:
print "_onFdRead failed,"
return
acceptor.onReadEvent()
def _onFdWrite(self, client_socket):
acceptor = self._acceptor_dict.get(client_socket, None)
if acceptor is None:
print "_onFdWrite failed,"
return
acceptor.onWriteEvent()
# 预备需要select的集合
def _prepare_select_sets(self):
inputs = copy.copy(self._listen_socket_list)
outputs = []
invalids = []
for acceptor in self._acceptor_dict.values():
if 1 != acceptor.client_status:
invalids.append(acceptor)
continue
inputs.append(acceptor.client_socket)
if acceptor.isNeedSend():
outputs.append(acceptor.client_socket)
for acceptor in invalids:
self._delTcpAcceptor(acceptor)
acceptor.onDisconnectEvent()
return inputs, outputs
# ServerInterface.serve_once()
def serve_once(self):
if 1 != self._is_started:
return
try:
inputs, outputs = self._prepare_select_sets()
readable, writable, exceptional = select.select(inputs, outputs, inputs, self._time_out)
# When timeout reached , select return three empty lists
if not (readable or writable or exceptional):
# print "Time out ! "
return
self._process_exceptional(exceptional)
self._process_writable_set(writable)
self._process_readable_set(readable)
except:
info = sys.exc_info()
for file, lineno, function, text in traceback.extract_tb(info[2]):
str_info = "{0} line:{1} in function:{2}".format(file, lineno, function)
print str_info
str_text = "** %s: %s" % info[:2]
print str_text
sys.exit(102)
def _process_readable_set(self, readable_set):
for readable_socket in readable_set:
if readable_socket in self._listen_socket_list:
self._onFdAccept(readable_socket)
else:
self._onFdRead(readable_socket)
def _process_writable_set(self, writable_set):
for writable_socket in writable_set:
self._onFdWrite(writable_socket)
pass
'''
for sock in writable:
try:
next_msg = message_queues[s].get_nowait()
except Queue.Empty:
print >>sys.stderr, ' ', s.getpeername(), 'queue empty'
outputs.remove(s)
else:
print >>sys.stderr, ' sending "%s" to %s' % \
(next_msg, s.getpeername())
s.send(next_msg)
'''
def _process_exceptional(self, exceptional_set):
for exceptional_socket in exceptional_set:
print "_process_exceptional:",exceptional_socket.fileno()
pass
class _Acceptor(object):
__slots__ = ['client_session_id', 'client_socket', 'client_addr', 'client_status', 'recv_packet_size',
'recv_buffer', 'send_buffer']
def __init__(self, client_session_id=-1, client_socket=None, client_addr=(), client_status=0):
self.client_session_id = client_session_id
self.client_socket = client_socket
self.client_addr = client_addr
self.client_status = client_status
self.recv_packet_size = 16 * 1024
self.recv_buffer = ''
self.send_buffer = ''
def onReadEvent(self):
while self.client_status == 1:
try:
data = self.client_socket.recv(self.recv_packet_size)
if not data:
print "client_socket.recv 0 from addr:{0} sessionid:{1}".format(self.client_addr,
self.client_session_id)
self.client_status = -1
return
self.recv_buffer += data
processed_size = self._process_recv_buffer()
if processed_size == len(self.recv_buffer):
self.recv_buffer = ''
elif processed_size < len(self.recv_buffer):
self.recv_buffer = self.recv_buffer[processed_size:]
elif processed_size == 0:
pass
else:
print "client_socket._process_recv_buffer error from addr:{0} sessionid:{1}".format(
self.client_addr, self.client_session_id)
self.client_status = -1
except socket.error, msg:
if msg.errno == errno.EAGAIN or msg.errno == errno.EWOULDBLOCK:
#print "onReadEvent EAGAIN or EWOULDBLOCK"
pass
else:
print "onReadEvent unhandle socket.error:{0}".format(msg)
self.client_status = -2
return
except Exception,e:
print "onReadEvent unhandle Exception:{0}".format(e)
self.client_status = -3
return
pass
def onDisconnectEvent(self):
if self.client_status == 0:
return
self.client_socket.close()
self.client_socket = None
self.client_status = 0
self.send_buffer=''
self.recv_buffer=''
def onWriteEvent(self):
if not self.isNeedSend():
return
ret = self.client_socket.send(self.send_buffer)
print "write:", ret, len(self.send_buffer),self.send_buffer
if ret == len(self.send_buffer):
self.send_buffer=''
return
self.send_buffer = self.send_buffer[ret:]
pass
#是否有发送的必要
def isNeedSend(self):
if self.client_status == 0:
return False
if len(self.send_buffer) == 0:
return False
return True
def sendData(self, data=""):
if self.client_status == 0:
return False
self.send_buffer += data
return True
def _process_recv_buffer(self):
pid=str(os.getpid())
print '{0}-recv:'.format(pid), len(self.recv_buffer),self.recv_buffer
self.sendData( pid+"say:"+self.recv_buffer)
return len(self.recv_buffer)
if __name__ == '__main__':
print __file__
serv = EchoServer(1234)
InterruptableTaskLoop(serv, 0.0).startAsForver()
客户端
# -*- coding: utf-8 -*-
# !/usr/bin/env python
###################################################
# Teaching Wisedom to My Computer,
# Please Call Me Croco,Fuck Your Foolishness.
##################################################
import sys
import socket
import select
import traceback
import errno
class ServerInterface(object):
# ServerInterface.start()
def start(self):
raise NotImplementedError()
# ServerInterface.stop()
def stop(self):
raise NotImplementedError()
# ServerInterface.serve_once()
def serve_once(self):
raise NotImplementedError()
# ServerInterface.notify()
def notify(self, message):
raise NotImplementedError()
#################################################################
class EchoClient(ServerInterface):
def __init__(self, connect_addr,connection_pool_size=1,echo_text='hello'):
self._connect_addr = connect_addr
self._connection_pool_size = connection_pool_size
self._time_out = 1
self._echo_text=echo_text
pass
# ServerInterface.start()
def start(self):
self._connector_dict = {}
self._is_started = 0
try:
for i in xrange(self._connection_pool_size):
connect_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect_socket.connect(self._connect_addr)
connect_socket.setblocking(False)
self._connector_dict[connect_socket] = _Connector(client_socket=connect_socket,client_status=1)
if i==0:
print "EchoClient::Start() connectOK to {0}".format(self._connect_addr)
self._is_started = 1
self._prepare_first_request()
return True
except:
(ErrorType, ErrorValue, ErrorTB) = sys.exc_info()
info = "connect failed:{0} {1} ".format(ErrorValue, self._connect_addr)
print info
self._is_started = 0
sys.exit(100)
return False
# ServerInterface.stop()
def stop(self):
for connector in self._connector_dict.values():
connector.onDisconnectEvent()
self._connector_dict.clear()
self._is_started = 0
def _onFdRead(self, client_socket):
connector = self._connector_dict.get(client_socket, None)
if connector is None:
print "_onFdRead failed,"
return
connector.onReadEvent()
def _onFdWrite(self, client_socket):
connector = self._connector_dict.get(client_socket, None)
if connector is None:
print "_onFdWrite failed,"
return
connector.onWriteEvent()
# 预备需要select的集合
def _prepare_select_sets(self):
inputs = []
outputs = []
invalids = []
for connector in self._connector_dict.values():
#print "_prepare_select_sets fd:{0} status:{1}".format(connector.client_socket.fileno(),connector.client_status)
if 1 != connector.client_status:
invalids.append(connector)
continue
inputs.append(connector.client_socket)
if connector.isNeedSend():
outputs.append(connector.client_socket)
for connector in invalids:
if connector.client_socket in self._connector_dict:
del self._connector_dict[connector.client_socket]
connector.onDisconnectEvent()
return inputs, outputs
# ServerInterface.serve_once()
def serve_once(self):
# if 1 != self._is_started:
# print "service is not started ok,so exit"
# sys.exit(102)
# return
try:
inputs, outputs = self._prepare_select_sets()
readable, writable, exceptional = select.select(inputs, outputs, inputs, self._time_out)
# When timeout reached , select return three empty lists
if not (readable or writable or exceptional):
#print "serve_once() select Time out ! "
return
self._process_exceptional(exceptional)
self._process_writable_set(writable)
self._process_readable_set(readable)
except:
info = sys.exc_info()
for file, lineno, function, text in traceback.extract_tb(info[2]):
str_info = "{0} line:{1} in function:{2}".format(file, lineno, function)
print str_info
str_text = "** %s: %s" % info[:2]
print str_text
sys.exit(102)
def _prepare_first_request(self):
send_buffer=self._echo_text
for connector in self._connector_dict.values():
connector.echo_text = send_buffer
connector.sendData(send_buffer)
print "_prepare_first_request fd:{0} send_buffer:{1}".format(connector.client_socket.fileno(),len(send_buffer))
pass
def _process_readable_set(self, readable_set):
if not readable_set:
return
for readable_socket in readable_set:
self._onFdRead(readable_socket)
def _process_writable_set(self, writable_set):
if not writable_set:
return
for writable_socket in writable_set:
self._onFdWrite(writable_socket)
pass
'''
for sock in writable:
try:
next_msg = message_queues[s].get_nowait()
except Queue.Empty:
print >>sys.stderr, ' ', s.getpeername(), 'queue empty'
outputs.remove(s)
else:
print >>sys.stderr, ' sending "%s" to %s' % \
(next_msg, s.getpeername())
s.send(next_msg)
'''
def _process_exceptional(self, exceptional_set):
if not exceptional_set:
return
for exceptional_socket in exceptional_set:
print "_process_exceptional:",exceptional_socket.fileno()
pass
class _Connector(object):
__slots__ = ['client_socket', 'client_status', 'recv_packet_size','recv_buffer', 'send_buffer','echo_text']
def __init__(self, client_socket=None, client_status=0):
self.client_socket = client_socket
self.client_status = client_status
self.recv_packet_size = 16 * 1024
self.recv_buffer = ''
self.send_buffer = ''
self.echo_text="I am Connector"
def onReadEvent(self):
if self.client_status != 1:
print "onReadEvent status error"
return
while self.client_status == 1:
try:
data = self.client_socket.recv(self.recv_packet_size)
if not data:
print "client_socket.recv 0 from addr:{0} sessionid:{1}".format(self.client_addr,
self.client_session_id)
self.client_status = -1
return
self.recv_buffer += data
processed_size = self._process_recv_buffer()
if processed_size == len(self.recv_buffer):
self.recv_buffer = ''
elif processed_size < len(self.recv_buffer):
self.recv_buffer = self.recv_buffer[processed_size:]
elif processed_size == 0:
pass
else:
print "client_socket._process_recv_buffer error from addr:{0} sessionid:{1}".format(
self.client_addr, self.client_session_id)
self.client_status = -1
except socket.error, msg:
if msg.errno == errno.EAGAIN or msg.errno == errno.EWOULDBLOCK:
#print "onReadEvent EAGAIN or EWOULDBLOCK"
pass
else:
print "onReadEvent unhandle socket.error:{0}".format(msg)
self.client_status = -2
return
except Exception,e:
print "onReadEvent unhandle Exception:{0}".format(e)
self.client_status = -3
return
def onDisconnectEvent(self):
if self.client_status == 0:
return
print "onDisconnectEvent fd:{0}".format( self.client_socket.fileno() )
self.client_socket.close()
self.client_socket = None
self.client_status = 0
self.recv_buffer=''
self.send_buffer=''
def onWriteEvent(self):
if not self.isNeedSend():
return
ret = self.client_socket.send(self.send_buffer)
print "write:", ret, self.send_buffer
if ret == len(self.send_buffer):
#print "clear send buffer"
self.send_buffer=''
return
self.send_buffer = self.send_buffer[ret:]
pass
def sendData(self, data=""):
if self.client_status != 1:
print "sendData Failed"
return False
self.send_buffer += data
return True
#是否有发送的必要
def isNeedSend(self):
if self.client_status == 0:
return False
if len(self.send_buffer) == 0:
return False
return True
def _process_recv_buffer(self):
print 'recv:', len(self.recv_buffer),self.recv_buffer
self.sendData(self.echo_text)
return len(self.recv_buffer)
import time
if __name__ == '__main__':
print "BEGIN"
cli = EchoClient( connect_addr=("127.0.0.1",1234),connection_pool_size=65,echo_text='1'*20)
cli.start()
while True:
cli.serve_once()
#time.sleep(0.1)
print "END"