不多解释,直接上代码,是我们之前做战斗服务器时搞得,翻出来分享一下,把业务那块的代码去掉了,只贴出核心代码
程序入口:
#!/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()