tcp_epoll_server.py
#https://www.jianshu.com/p/cdfddb026db0
#https://github.com/fschr/simpletcp/blob/master/simpletcp/serversocket.py
#https://stackoverflow.com/questions/16745409/what-does-pythons-socket-recv-return-for-non-blocking-sockets-if-no-data-is-r
#http://scotdoyle.com/python-epoll-howto.html
import signal, os
import threading
import socket
import select
import errno
SERVER_ERR_INVAL=-1
class TcpServer:
def __init__(self, mode, port,callback):
self._thread = None
self._thread_terminate = False
# localhost -> (127.0.0.1)
# public -> (0.0.0.0)
# otherwise, mode is interpreted as an IP address.
if mode == "localhost":
self.ip = mode
elif mode == "public":
self.ip ="0.0.0.0"
else:
self.ip ="127.0.0.1"
self.port = port
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.setblocking(False)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind((self.ip, self.port))
self.connections={}
self.callback =callback
self._socket.listen(128)
self._epl= select.epoll()
self._epl.register(self._socket.fileno(),select.EPOLLIN)
def loop_start(self):
if self._thread is not None:
return
self._thread_terminate = False
self._thread = threading.Thread(target=self._thread_main)
#self._thread.daemon = True
self._thread.start()
def loop_stop(self, force=False):
if self._thread is None:
return SERVER_ERR_INVAL
self._thread_terminate = True
if threading.current_thread() != self._thread:
self._thread.join()
self._thread = None
def loop_once(self):
epoll_list = self._epl.poll(0)
for fd,events in epoll_list:
if fd == self._socket.fileno():
conn,addr =self._socket.accept()
conn.setblocking(False)
self.connections.update({conn.fileno():conn})
self._epl.register(conn.fileno(), select.EPOLLIN)
elif events == select.EPOLLIN:
print("in event")
buffer=b""
count=0
try:
while True:
msg= self.connections[fd].recv(1500)
count+=1
if msg:
buffer+=msg
else:
if buffer:
self.callback(self.connections[fd],buffer)
buffer=b""
self._epl.unregister(fd)
self.connections[fd].close()
self.connections.pop(fd)
break
except socket.error as e:
err = e.args[0]
print (err,count)
if buffer:
ret=self.callback(self.connections[fd],buffer)
if ret:
self._close(fd)
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
pass
else:
self._close(fd)
def _thread_main(self):
while True:
if self._thread_terminate is True:
break
self.loop_once(retry_first_connection=True)
def _close(self,fd):
if fd==self._socket.fileno():
self._epl.unregister(fd)
self._socket.close()
elif fd in self.connections:
self._epl.unregister(fd)
self.connections[fd].close()
self.connections.pop(fd)
def shut_down(self):
for fd, conn in self.connections.items():
self._epl.unregister(fd)
conn.close()
self.connections.clear()
self._close(self._socket.fileno())
def echo_back(conn,buffer):
print(buffer.decode('utf-8'))
conn.sendall(buffer)
return True
Terminate=False
def signal_handler(signum, frame):
global Terminate
Terminate =True
#netstat -tunlp | grep port
if __name__ == '__main__':
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGHUP, signal_handler) # ctrl+c
signal.signal(signal.SIGTSTP, signal_handler) #ctrl+z
echo_server=TcpServer("localhost",3345,echo_back)
while True:
echo_server.loop_once()
if Terminate:
echo_server.shut_down()
break
print("stop")
The client I use during test, tcp_client.py.
#https://blog.csdn.net/jerryhanjj/article/details/69047515
import socket
if __name__ == '__main__':
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 3345))
sendbuf ="hello world,dididdidididididididididddididdidi"
client.send(sendbuf.encode('utf-8'))
recvbuf = client.recv(1024)
print(recvbuf.decode('utf-8'))
client.close()
print('Connection was closed...')
Reference:
[1] How To Use Linux epoll with Python
[2] python socket编程 tcp 简单示例
网友评论