首页 > 技术文章 > [记录]Python的master-worker和epoll模式

wsjhk 2018-03-03 20:45 原文

#master-worker模型:
#coding:utf-8
import os
import sys
import socket
import time
import traceback
import errno
import signal

class Worker(object):
    def __init__(self, sock):
        self.sock = sock

    def accept(self):
        client, addr = self.sock.accept()
        client.setblocking(True)
        self.handle(client, addr)

    def init_process(self):
        self.sock.setblocking(False)
        while True:
            try:
                time.sleep(1)
                self.accept()
                continue
            except Exception as e:
                msg = traceback.format_exc()
                with open("sub_"+str(os.getpid())+".txt","a") as f:
                    f.write(msg+"\n")
                if hasattr(e, "errno"):
                    if e.errno not in (errno.EAGAIN, errno.ECONNABORTED, errno.EWOULDBLOCK):
                        msg = traceback.format_exc()
                else:
                    raise

    def handle(self, client, addr):
        data = client.recv(1024)
        pid = os.getpid()
        data += str(pid)
        # print("receive:{} pid:{}".format(data, pid))
        client.send("back:"+data)
        client.close()

class Server(object):
    def __init__(self):
        self.port = ("127.0.0.1", 8004)
        self.sock = socket.socket()
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(self.port)
        self.sock.setblocking(False)
        self.sock.listen(5)
        self.WORKERS = {}

    def run(self):
        self.init_signals()
        for i in range(2):
            self.spawn_worker()
            print(i)
        # self.spawn_worker()
        for k in self.WORKERS:
            print(k, self.WORKERS[k])
        while True:
            import time
            time.sleep(3)
            try:
                pid, status = os.waitpid(-1, os.WNOHANG)
                print("kill  pid: {}, status: {}".format(pid, status))
            except os.error:
                print("error")

    def init_signals(self):
        signal.signal(signal.SIGTTIN, self.incr_one)
        signal.signal(signal.SIGTTOU, self.decr_one)

    def incr_one(self, signo, frame):
        self.spawn_worker()
        for k in self.WORKERS:
            print(k, self.WORKERS[k])


    def decr_one(self, signo, frame):
        for k in self.WORKERS:
            os.kill(k, signal.SIGKILL)
            break

    def spawn_worker(self):
        worker = Worker(self.sock)

        pid = os.fork()
        if pid != 0:
            worker.pid = pid
            self.WORKERS[pid] = worker
            return pid

        worker.pid = os.getpid()
        worker.init_process()
        sys.exit(0)

if __name__ == "__main__":
    server = Server()
    server.run()

=======================================================================
epoll模型:
server:
#-*- coding:utf8 -*-  
import socket  
import select  
import os  
  
address = "0.0.0.0"  
port = 10001  
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
  
def main():  
     global address,port,sock  
     epoll = select.epoll()  
     #获取创建好的sock的文件描述符  
     fd = sock.fileno()  
     sock.bind((address,port))  
     sock_dict = {}  
     sock_dict[fd] = sock  
     #对该sock进行注册  
     epoll.register(fd,select.EPOLLIN)  
     sock.listen(5)  
     while True:  
         events = epoll.poll(1)  
         for fileno,event in events:  
         #获取到的文件描述符和sock的相同就说明是一个新的连接  
             if fileno == fd:  
                 (client,address) = sock.accept()  
                 print address  
                 client.setblocking(0)  
         #将新的连接进行注册,用来接收消息  
                 epoll.register(client.fileno(),select.EPOLLIN)  
                 sock_dict[client.fileno()] = client  
            elif event & select.EPOLLIN:  
                 print "fileno:",fileno  
                 data = sock_dict[fileno].recv(128)  
                 if data == '你好':  
                     print "Data:",data.decode('UTF-8')  
                     sock_dict[fileno].send("你好")  
                elif len(data) == 0:  
                     print "线路%d已下线"%fileno  
                     epoll.unregister(fileno)  
                else:  
                     print "Data:",data  
if __name__ == '__main__':  
    main()

client:
#coding: UTF-8  
    
import socket  
import select  
  
address = "127.0.0.1"  
port = 10001  
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
  
def main():  
    global address,port,sock  
    sock.connect((address,port))  
    epoll = select.epoll()  
    fd = sock.fileno()  
    #这里的epoll注册只是用来异步接收服务端发过来的消息  
    epoll.register(fd,select.EPOLLIN)  
    while True:  
        events = epoll.poll(1)  
        for fileno,event in events:  
            if fileno == fd:  
                if event & select.EPOLLIN:  
                    data = sock.recv(128)  
                    print data  
        data = raw_input(">")  
        if data == 'q':  
            break  
        elif data == '':  
            print "不能发送空消息"  
            continue  
        sock.send(data)  
    sock.close()  
main()

  

推荐阅读