通过TCP协议和客服端通信。socketserver库实现。
############ server #######################
from socketserver import BaseRequestHandler,TCPServer
class EchoHandler(BaseRequestHandler):
def handle(self):
print("Got connection from,",self.clinet_address)
while True:
msg=self.request.recv(8192)
if not msg:
break
self.request.send(msg)
serv=TCPServer(('',20000),EchoHandler)
serv.serve_forever()
############### client###################
from socket import socket,AF_INET,SOCK_STREAM
s=socket(AF_INET,SOCK_STREAM)
s.connect(('localhost',20000))
s.send(b'hello') # 5
s.recv(8192) # b'Hello'
很容易定义一个不同的处理器,StreamRequestHandler基类将一个类文件接口放置在底层socket上例子:
from socketserver import StreamRequestHandler,TCPServer
class EchoHandler(StreamRequestHandler):
def handle(self):
print('got connection from',self.client_address)
# self.rfile is a file-like object for reading
for lin in self.rfile:
#self.wfile in a file-like object for writing
self.wfile.write(line)
serv=TCPServer(('',20000),EchoHandler)
serv.server_forerver()
多线程服务器
想要处理多个客户端,可以初始化一个ForkingTCPServer
或者是ThreadingTCPServer
对象。
from socketserver import ThreadingTCPServer
serv=ThreadingTCPServer(('',20000),EchoHandler)
serv.server_forever()
使用fork或线程潜在问题就是每个客服端连接创建一个新的进程或线程。由于客服端连接数是没有限制的,因此一个恶意的黑客可以同时发送大量的连接让你的服务器奔溃。可以先预先分配带下的工作线程池或进程池。首先创建一个非线程服务器,然后在一个线程池中使用server_forever()
方法来启动它们。
if __name__ == '__main__':
from threading import Thread
NETWORKS=16
serv=TCPServer(('',20000),EchoHandler)
for n in range(NETWORKS):
t = Thread(target=serv.serve_forever)
t.daemon=True
t.start()
serv.serve_forever()
一般来讲,一个TCPServer在实例化的时候会绑定并激活相应的socket。不过,有时候通过设置某些选项去调整底下的socket,可以设置参数bind_and_activate=False
。
if __name__ =='__main__':
serv=TCPServer((,20000),EchoHandler,bind_and_activate=False)
# set up various socket options
serv.socket.setsocket(socket.SOL_SOCKET,socket.SO_REUSERADDR,True)
#bind and activate
serv.server_bind()
serv.server_activate()
serv.serve_forever()