1、 SocketServer最简单的使用方法:
(1) 创建一个Handler类,继承自BaseRequestHandler,重写其handle(),在该方法中完成对请求的处理。
(2) 实例化一个Server类对象(根据不同的server类型选择不同的Server类)。并将IP、端口和Handler类传递给Server的构造函数。
(3) 调用server对象的server_forever()开启服务。
2、 Socket.server提供的类类型
(1) socketserver中类分为三种类型。一是Server类:BaseServer/TCPServer/UDPServer用来接收客户的请求。TCPServer处理TCP请求,UDPServer处理UDP请求。BaserServer是基类,不能直接使用。TCPServer继承自BaseServer,UDPServer继承自TCPServer。暂时不明白为什么UDPServer要继承自TCPServer,后面再说。
(2) 二是Handler类:BaseRequestHandler/DatagramRequestHandler/StreamRequestHandler用来处理每一个客户请求。一般用使用BaseRequestHandler就行,但StreamRequestHandler/DatagramRequestHandler提供了一些特别的功能,前者用来处理流式(TCP)请求,后者处理数据报(UDP)请求。Server每收到一个客户请求就会创建一个Handler类示例来处理该请求。默认情况下,TCPServer/UDPServer是单进程单线程的模型,依次处理每个客户请求,一个请求处理完毕才能接着处理下一个请求。
(3) 三是MixIn类:ForkingMixIn/ThreadingMixIn用来为Server提供多进程/多线程并发处理能力的。ForkingMixIn是多进程模型,ThreadingMixin是多线程模型。这里特别巧妙的是,你只要创建一个类,同时继承Server类和MixIn类就能自动获得并发处理请求的能力。该模块本身就直接提供了这种类。
3、 ThreadingTCPServer/TCPServer/ForkingTCPServer的区别:
这三个类其实就是对接收到request请求后的不同处理方法。
TCPServer是接收到请求后执行handle方法,如果前一个的handle没有结束,那么其他的请求将不会受理,新的客户端也无法加入。
而ThreadingTCPServer和ForkingTCPServer则允许前一连接的handle未结束也可受理新的请求和连接新的客户端,区别在于前者用建立新线程的方法运行handle,后者用新进程的方法运行handle。
#练习9:SocketServer
服务端:
import SocketServer
import threading
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
while True:
self.data = self.request.recv(1024).strip()
cur_thread = threading.current_thread()
print cur_thread
if not self.data:
print u"客户端:%s 退出!" % self.client_address[0]
break
print u"%s 内容:%s" % (self.client_address[0], self.data)
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "47.98.155.208", 8001
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
客户端:
if __name__=="__main__":
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect(("'47.98.155.208', 8001"))
import time
time.sleep(2)
socket.send("ls -al /home/WANGJING"+"
")
print socket.recv(1024).deconde("gbk")
socket.close()
fd:file descriptor 文件描述符
fd_r_list, fd_w_list, fd_x_list = select.select(rlist, wlist, xlist, [timeout])
参数: 可接受四个参数(前三个必须)
rlist: wait until ready for reading
wlist: wait until ready for writing(一般不使用)
xlist: wait for an “exceptional condition”
timeout: 超时时间
#练习10:select 单线程实现多线程效果
服务端:
import socket
import select
s = socket.socket()
s.bind(('127.0.0.1', 8888))
s.listen(5)
r_list = [s, ]
num = 0
while True:
print u"开始进入监听状态..."
rl, wl, error = select.select(r_list, [], [], 10)
# 第一次执行循环体:客户端建立的连接的时候,rl和r_list分别是[s,]和[s,]
# 执行连接之后,r_list变为了[s,conn]
# 第二次执行循环体:rl和r_list分别是[conn,]和[s,conn],执行else逻辑
#
#第n次执行循环体:rl和r_list分别是[conn,]和[s,conn],执行else逻辑
num += 1
print u'执行次数%s'% num
print("rl's length is %s" % len(rl))
print("r_list length %s" % len(r_list))
print "--------------length:", len(rl)
print [i for i in rl]
for fd in rl:
if fd == s:
conn, addr = fd.accept()
r_list.append(conn)
msg = conn.recv(200)
conn.sendall(('first----%s' % conn.fileno()).encode("gbk"))
else:
try:
msg = fd.recv(200)
fd.sendall('second'.encode())
except ConnectionAbortedError:
r_list.remove(fd)
s.close()
客户端:
import socket
flag = 1
s = socket.socket()
s.connect(('127.0.0.1', 8888))
while flag:
input_msg = raw_input('input>>>')
if input_msg == '0':
break
s.sendall(input_msg.encode())
msg = s.recv(1024)
print(msg.decode())
s.close()