Найти - Пользователи
Полная версия: Сетевой сервис(служба) под Windows с использование asyncore
Начало » Network » Сетевой сервис(служба) под Windows с использование asyncore
1
sinopteek
Хочу запустить код на python как службу под Windows.

Код самого сервиса есть. a123.py
debug = False

import asyncore
import socket

import random

import CRC16
import Int_Str

def make_packet_ans(Command, derection, data = None):
u'''подготавливаем пакет для посылки'''
#собираем пакет в сообтветствии с ыорматом
packet = Command + derection
if data:
#обрезаем ответ до двух байт
if data > 1<<16:
data = data % 1<<16
packet = packet + chr(data/256) + chr(data%256)
else:
packet = packet + '\x00\x00'

#вычисляем CRC
crc = CRC16.generate_crc(packet)
crc_str = Int_Str.int2str(command=crc, message_length=2)
#добавляем CRC
packet += crc_str

if debug:
Int_Str.print_command(packet)

#возвращаем пакет
return packet

def check_packet(packet):
u'''проверяем принятый пакет CRC16'''
#вычисляем CRC для информациионной части
crc = CRC16.generate_crc(packet[:-2])
crc_str = Int_Str.int2str(command=crc, message_length=2)

if debug:
Int_Str.print_command(crc),Int_Str.print_command(packet[-2:])

#возвращаем результат
if crc_str == packet[-2:]:
return True
else:
return False

class EchoHandler(asyncore.dispatcher_with_send):

def handle_read(self):
print "readed"
data = self.recv(6)
if len(data) == 6:
if check_packet(data):
INT = random.randint(0,1<<16)
INT_0 = INT / (1<<8)
INT_1 = INT % (1<<8)
#data = data[:2]+chr(INT_0)+chr(INT_1)+data[-2:]
data = make_packet_ans(Command = data[0], derection=data[1], data = INT)
self.send(data)
else:
self.send(data)
self.close()

def handle_expt(self):
self.close() # connection failed, shutdown

class EchoServer(asyncore.dispatcher):

def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)

def handle_accept(self):
pair = self.accept()
if pair is None:
pass
else:
sock, addr = pair
print 'Incoming connection from %s' % repr(addr)
handler = EchoHandler(sock)

if __name__ == "__main__":
server = EchoServer(host = 'localhost', port = 1600)
asyncore.loop(0.1)
Есть пример запуска кода как сервиса service_test.py
import win32serviceutil
import win32service
import win32event
import servicemanager

import a123
import asyncore

class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "DummyService"
_svc_display_name_ = "Dummy Service"
_svc_description_ = "Dummy Service Description"

def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
self.hWaitResume = win32event.CreateEvent(None, 0, 0, None)
self.timeout = 2000 #Пауза между выполнением основного цикла службы в миллисекундах
self.resumeTimeout = 1000
self._paused = False

def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING, 1000)
win32event.SetEvent(self.hWaitStop)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))

def SvcPause(self):
self.ReportServiceStatus(win32service.SERVICE_PAUSE_PENDING)
self._paused = True
self.ReportServiceStatus(win32service.SERVICE_PAUSED)
servicemanager.LogInfoMsg("The %s service has paused." % (self._svc_name_, ))

def SvcContinue(self):
self.ReportServiceStatus(win32service.SERVICE_CONTINUE_PENDING)
win32event.SetEvent(self.hWaitResume)
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
servicemanager.LogInfoMsg("The %s service has resumed." % (self._svc_name_, ))


def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()

#В этом методе реализовываем нашу службу
def main(self):
#Здесь выполняем необходимые действия при старте службы
servicemanager.LogInfoMsg("Hello! I'm a Dummy Service.")

server = a123.EchoServer(host = 'localhost', port = 1600)

while True:
#Здесь должен находиться основной код сервиса
servicemanager.LogInfoMsg("I'm still here.")

asyncore.loop(0.1)

servicemanager.LogInfoMsg("after loop")

# Проверяем не поступила ли команда завершения работы службы
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
if rc == win32event.WAIT_OBJECT_0:
# Здесь выполняем необходимые действия при остановке службы
servicemanager.LogInfoMsg("Bye!")
break

# Здесь выполняем необходимые действия при приостановке службы
if self._paused:
servicemanager.LogInfoMsg("I'm paused... Keep waiting...")
# Приостановка работы службы
while self._paused:
# Проверям не поступила ли команда возобновления работы службы
rc = win32event.WaitForSingleObject(self.hWaitResume, self.resumeTimeout)
if rc == win32event.WAIT_OBJECT_0:
self._paused = False
# Здесь выполняем необходимые действия при возобновлении работы службы
servicemanager.LogInfoMsg("Yeah! Let's continue!")
break

if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
В нём подправил asyncore.loop(0.1)

после этого необходимо зарегестрировать службу - в консоли
python service_test.py install
Теперь служба устанавливается(появляется в списке служб), запускается как служба(необходимо запускать подолнительно), код работает, но служба не хочет останавливаться вообще.

В связи с этим несколько вопросов:
Как я понимаю asyncore.loop(0.1) не завершается, по крайней мере не в лог строчка после него не попадает, хотя, если запустить отдельным потоком, то по таймауту завершается. В чём может быть причина?
Как узнать, что asyncore.loop уже запущен, а то может быть я просто создаю кучу обработчиков?
Возможно ли принудительно завершить asyncore.loop? На случай, если вдруг захочу остановить сервис не дожидаясь окончания обработки принятых пакетов(они могут идти практически бесконечно).

На 2,3 вопросы в документации ответов не нашёл
sinopteek
Сам отвечаю на свои вопросы:
asyncore.loop(0.1)
не завершается, чтобы завершался необходимо задать количество повторов
asyncore.loop(timeout=0.2,use_poll=True, count=50)
Код из a123.py не запускался, т.к. не мог импортировать модуль, который лежал в той же папке, что и запускаемый, просто не находил его. Можно, конечно, скопировать необходимые файлы в системную папку или прописать дополнительно путь, но IMHO не красиво.
Поэтому переписал запуск модуля внутри службы(service_test.py):
      asyncore.loop(0.1)
на
      file_path = "C:\\..\\a123.py"
try:
path,file_name = os.path.split(file_path)

#Подготавливаем процесс
proc= subprocess.Popen("python "+file_name,
shell = False,
cwd = path)
#выполняем его
proc.communicate()
except:
pass
, теперь работает :D

p.s. можно также из консоли start, stop, remove служб
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB