python非阻塞服务器实现

不多解释,直接上代码,是我们之前做战斗服务器时搞得,翻出来分享一下,把业务那块的代码去掉了,只贴出核心代码


程序入口:

#!/usr/bin/env python
# encoding: utf-8
"""
Server.py

Create by sunshaolei at 12-9-3
Email: [email protected]
"""
import sys
from servercore.Client import Client
from servercore.HandlerPool import HandlerPool

class Server():
    """
    """
    def __init__(self, host, port):
        """
        """
        self.client = Client(host, port)
        self.handlerPool = HandlerPool(1)

    def start(self):
        """
        """
        self.client.start()
        self.handlerPool.start()

        self.handlerPool.join()


server = Server(sys.argv[1], sys.argv[2])
server.start()


客户端连接:

#!/usr/bin/env python
# encoding: utf-8
"""
Client.py

Create by sunshaolei at 12-9-3
Email: [email protected]
"""
import socket
import select
import threading
import struct
import copy
import time
from buffer.DataBase import DataBase
from buffer.Sequence import Sequence
from utils.Util import Util


class Client(threading.Thread):
    """
    """
    MAX_CLIENT = 1024 * 2
    MAX_BUFFER = 1024*10240
    RECV_LEN = 1024
    ENDIAN = DataBase.HIGHT_ENDIAN

    def __init__(self, host, port):
        """
        """
        threading.Thread.__init__(self, name='Client')

        self.client_buffer = {}     # 收取数据buff
        self.sequence = Sequence()

        self.host = host
        self.port = int(port)

        self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.sock.bind((self.host, self.port))
        self.sock.setblocking(0)
        self.sock.listen(Client.MAX_CLIENT)

        self.onlineSocketList = [self.sock]

    def run(self):
        """
        """
        while True:
            infds, outfds, errfds = select.select(self.onlineSocketList, self.onlineSocketList, self.onlineSocketList)
            for infd in infds:
                if infd is self.sock:
                    connect, addr = self.sock.accept()
                    Util.write_log('info', 'new connect by: %s:%s' % addr)
                    connect.setblocking(0)
                    self.onlineSocketList.append(connect)
                else:
                    try:
                        self.recv(infd)
                    except:
                        self.disconnect(infd)

            for outfd in outfds:
                try:
                    self.send(outfd)
                except :
                    self.disconnect(outfd)

            for errfd in errfds:
                self.disconnect(errfd)

            time.sleep(0.001)


    def recv(self, fd):
        """
        接收数据处理
        """
        if fd not in self.client_buffer:
            self.client_buffer[fd] = ''

        if len(self.client_buffer[fd]) + Client.RECV_LEN < Client.MAX_BUFFER:
            buff = fd.recv(Client.RECV_LEN)
            if not buff:
                self.disconnect(fd)
                return

            self.client_buffer[fd] += buff

            data = self.client_buffer[fd]
            num = 0     # 放置错误的数据格式导致死循环的
            while len(data) > 4 and num < 20:
                num += 1
                tag = '>i' if Client.ENDIAN == 1 else 'i'
                data_len = struct.unpack(tag, data[0:4])[0]
                if (len(data)-4) >= data_len:     # 满足条件
                    database = DataBase(fd, data[4:data_len+4])
                    self.sequence.inQueue.put(database)
                    self.client_buffer[fd] = data[data_len+4:]
                    num = 0     # 如果有数据置为0

                data = self.client_buffer[fd]


    def send(self, fd):
        """
        发送数据
        """
        database_list = self.sequence.getOut(fd)
        if not database_list:
            return
        try:
            for database in database_list:
                database.fd.send(database.buffer)
        except Exception:
            self.disconnect(fd)


    def disconnect(self, fd):
        """
        """
        if fd in self.onlineSocketList:
            self.onlineSocketList.remove(fd)
        if fd in self.client_buffer:
            self.client_buffer.pop(fd)

        self.sequence.getOut(fd)
        fd.close()

逻辑处理:

#!/usr/bin/env python
# encoding: utf-8
"""
HandlerPool.py

Create by sunshaolei at 12-9-3
Email: [email protected]
"""
import threading
from servercore.Handler import Handler

class HandlerPool(threading.Thread):
    """
    """
    def __init__(self, handlerNum=1):
        """
        """
        self.handlerNum = handlerNum
        self.threads = []

    def start(self):
        """
        """
        self.createThread(self.handlerNum)
        self.wait_for_complete()

    def createThread(self, num):
        for i in range(num):
            thread = Handler(i)
            thread.start()
            self.threads.append(thread)

    def wait_for_complete(self):
        #等待所有线程完成。
        while len(self.threads):
            thread = self.threads.pop()
            if thread.isAlive():
                thread.join()



#!/usr/bin/env python
# encoding: utf-8
"""
Handler.py

Create by sunshaolei at 12-9-19
Email: [email protected]
"""
import threading
import traceback
from Game.fight_service import FightService
from buffer.Sequence import Sequence
from utils.Util import Util

class Handler(threading.Thread):
    """
    """
    def __init__(self, threadId):
        """
        """
        threading.Thread.__init__(self, name='Hander_%s' % threadId)

        self.sequence = Sequence()

    def run(self):
        """
        """
        while True:
            database = self.sequence.inQueue.get()

            try:
                # 此处为业务入口,可以根据 moduleId,actionId分发进行数据解包,并执行相关处理,此处省略了
                moduleId = database.getByte()
                actionId = database.getByte()
                data = database.getUTF()

                FightService.app_server_msg(database.fd, moduleId, actionId, data)
            except:
                exstr = traceback.format_exc()
                Util.write_log('err', exstr)



#!/usr/bin/env python
# encoding: utf-8
"""
DataBase.py

Create by sunshaolei at 12-9-19
Email: [email protected]
"""
import struct

class DataBase(object):
    """
    """
    HIGHT_ENDIAN = 1
    LOW_ENDIAN = 0
    def __init__(self, fd, buff=None, endian=HIGHT_ENDIAN):
        """
        """
        self.fd = fd
        self.pos = 0
        self.endian = endian
        self.buffer = buff if buff else ''

    def reset(self):
        """
        """
        self.pos = 0

    def getInt(self):
        """
        """
        tag = '>i' if self.endian == DataBase.HIGHT_ENDIAN else 'i'
        result = struct.unpack(tag, self.buffer[self.pos:self.pos+4])[0]
        self.pos += 4
        return result

    def getShort(self):
        """
        """
        tag = '>h' if self.endian == DataBase.HIGHT_ENDIAN else 'h'
        result = struct.unpack(tag, self.buffer[self.pos:self.pos+2])[0]
        self.pos += 2
        return result

    def getByte(self):
        """
        """
        tag = 'b'
        result = struct.unpack(tag, self.buffer[self.pos:self.pos+1])[0]
        self.pos += 1
        return result

    def getUTF(self):
        """
        """
        tag = '>h' if self.endian == DataBase.HIGHT_ENDIAN else 'h'
        length = struct.unpack(tag, self.buffer[self.pos:self.pos+2])[0]
        self.pos += 2

        tag = '%ss' % (length)
        result = struct.unpack(tag, self.buffer[self.pos:self.pos+length])[0]
        self.pos += length
        return result

    def setInt(self, value):
        """
        """
        tag = '>i' if self.endian == DataBase.HIGHT_ENDIAN else 'i'
        self.buffer += (struct.pack(tag, value))
        return True

    def setShort(self, value):
        """
        """
        tag = '>h' if self.endian == DataBase.HIGHT_ENDIAN else 'h'
        self.buffer += (struct.pack(tag, value))
        return True

    def setByte(self, value):
        """
        """
        tag = 'b'
        self.buffer += (struct.pack(tag, value))
        return True

    def setUTF(self, value):
        """
        """
        tag = '>h' if self.endian == DataBase.HIGHT_ENDIAN else 'h'
        length = len(value)
        self.buffer += (struct.pack(tag, length))

        tag = '%ss' % (length)
        self.buffer += (struct.pack(tag, value))
        return True


#!/usr/bin/env python
# encoding: utf-8
"""
Sequence.py

Create by sunshaolei at 12-9-19
Email: [email protected]
"""
import threading
from Queue import Queue
from utils.Singleton import Singleton

buffLock = threading.RLock()

class Sequence(Singleton):
    """
    """
    def __init__(self):
        """
        """
        self.out_buff = {}

        self.inQueue = Queue(64)

    def getOut(self, k):
        """
        """
        buffLock.acquire()
        data = None
        if k in self.out_buff:
            data = self.out_buff.pop(k)
        buffLock.release()
        return data

    def addOut(self, k, v):
        """
        """
        buffLock.acquire()
        if k not in self.out_buff:
            self.out_buff[k] = []

        self.out_buff[k].append(v)
        buffLock.release()



你可能感兴趣的:(python非阻塞服务器实现)