【Python】socket编程-3

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"+"\n")
    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()

猜你喜欢

转载自www.cnblogs.com/jingsheng99/p/9006453.html