标准类库 - 因特网协议与支持之socketserver
by:授客 QQ:1033553122
socketserver 模块,简化网络服务编写任务。
创建服务的步骤
1 通过子类化BaseRequestHandler 类,创建一个请求处理程序,并且重写handle()方法,该方法将处理接收到的请求
2 传递服务器地址和请求处理程序类参数,实例化server类(如TCPServer)
3 调用server对象的handle_request()、serve_forever()方法,处理单个、多个请求
实例
socketserver.TCPServer
服务端(单线程服务器)
#!/usr/bin/env python 3.4.0
#-*- encoding:utf-8 -*-
__author__ = 'shouke'
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
供server使用的RequestHandler类.
每个客户端连接连接到服务器时都会被初始化一次,并且必须重写handle()方法以便同客户端交流。
"""
def handle(self):
while True:
# self.request即为与客户端连接的TCP socker
self.data = self.request.recv(1024).decode('utf-8').strip()
print('receive data from client[host:%s port:%s]:%s' % (self.client_address[0], self.client_address[1], self.data))
if self.data == 'bye':
self.request.sendall(bytes('bye', encoding='utf-8'))
self.request.close()
break
else:
self.request.sendall(self.data.upper().encode('utf-8'))
if __name__ == '__main__':
# 创建TCPSocket服务器,绑定到10.118.52.26地址上,端口8000
server = socketserver.TCPServer(('10.118.52.26', 8000), MyTCPHandler)
# 激活服务器,让服务器一直运行,直到按Ctrl+C
server.serve_forever()
客户端
#!/usr/bin/env python 3.4.0
#-*- encoding:utf-8 -*-
__author__ = 'shouke'
import socket
import time
if __name__ == '__main__':
if_sock_connected = False
try:
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to server and send data
sock.connect(('10.118.52.26', 8000))
if_sock_connected = True # 标记socket是否已连接
i = 0
while i < 100:
if i == 6:
sock.sendall(bytes('bye\n', "utf-8"))
else:
sock.sendall(bytes('hello world with tcp\n', "utf-8"))
# Receive data from the server
received = str(sock.recv(1024), "utf-8")
logger.info('receive data from server:%s' % received)
if received == 'bye':
break
time.sleep(5)
i += 1
except Exception as e:
logger.error('程序运行出错:%s' % e)
finally:
if if_sock_connected:
sock.close()
运行结果
函数说明:
BaseServer.serve_forever(poll_interval=0.5)
处理shudown请求除外的请求。
有关socket说明
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
使用给定的地址家族,socket 类型,协议号创建一个新的socket。
family:默认为AF_INET,其它可选值有AF_INET6, AF_UNIX, AF_CAN or AF_RDS
type:默认为SOCK_STREAM,其它可选值有 SOCK_DGRAM, SOCK_RAW ,或者其它SOCK_XXX常量
protocol:通常为0或者忽略,当family为AF_CAN时,为CAN_RAW、CAN_BCM
Socket 对象
socket.close()
标记socket为closed
close()释放与连接关联的资源,但不一定立即关闭连接。如果要及时关闭连接,请在调用close()之前调用shutdown()。
socket.connect(address)
连接给定地址的远程socket
socket.recv(bufsize[, flags])
从socket接收数据。返回值即为接收的数据。
buffsize:每次接收的最大数据量。.
flags默认为0
注意:为了同硬件和网络设备最佳匹配,buffsize应该为一个相对小的2次幂,比如4096
socket.sendall(bytes[, flags])
发送字节数据到socket。不同于send方法,该方法会持续发送bytes参数给定的数据,直到所有数据被发送、错误发生。如果发送成功,则返回None,否则抛出异常。没有方法判断到底成功发送了多少数据
socket.send(bytes[, flags])
发送字节数据到socket。返回发送字节数,如果只传输了部分数据,程序会尝试发送剩余数据。
更多资料参考官方文档,socket模块
服务端(多线程服务器)
#!/usr/bin/env python 3.4.0
#-*- encoding:utf-8 -*-
__author__ = 'shouke'
import socket
import threading
import socketserver
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
# self.request即为与客户端连接的TCP socker
self.data = self.request.recv(1024).decode('utf-8').strip()
cur_thread = threading.current_thread()
print('%s receive data from client[host:%s port:%s]:%s' % (cur_thread.name, self.client_address[0], self.client_address[1], self.data))
if self.data == 'bye':
self.request.sendall(bytes('bye', encoding='utf-8'))
self.request.close()
break
else:
self.request.sendall((cur_thread.name + ' ' + self.data.upper()).encode('utf-8'))
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))
if __name__ == "__main__":
# 如果设置端口为0,则表示任意未被占用端口
HOST, PORT = "localhost", 9000
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# 开启该server的一个线程,该线程会为每个请求开启更多的线程
server_thread = threading.Thread(target=server.serve_forever)
# server退出时,终止线程
#server_thread.setDaemon(True)
server_thread.start()
print("Server loop running in thread:", server_thread.name)
# server.shutdown()
# server.server_close()
客户端
#!/usr/bin/env python 3.4.0
#-*- encoding:utf-8 -*-
__author__ = 'shouke'
import socket
import time
if __name__ == '__main__':
if_sock_connected = False
try:
# 创建一个socket (SOCK_STREAM 表示为TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
sock.connect(('localhost', 9000))
# 发送数据
if_sock_connected = True
i = 0
while i < 100:
if i == 6:
sock.sendall(bytes('bye\n', "utf-8"))
else:
sock.sendall(bytes('hello world with tcp\n', "utf-8"))
print("sent data to server:{}".format(bytes('hello world with tcp\n', "utf-8")))
# 从服务器接收数据
received = str(sock.recv(1024), "utf-8")
print('receive data from server:%s' % received)
if received == 'bye':
break
time.sleep(1)
i += 1
except Exception as e:
print('程序运行出错:%s' % e)
finally:
if if_sock_connected:
sock.close()
运行结果
更多资料,烦参考官方文档,socketserver模块。