LINUX.ORG.RU

скрипт с сокетами в python в какой-то момент сжирает ресурсы процессора - кажется, нужна помощь

 , ,


0

1

я новичок (чорт, впору делать майки novichok)

сделал на питоне некий прокси-скрипт, который слушает на двух портах и потом передает услышанное клиенту на третьем порте. вроде бы все более-менее работает с одиночными подключениями, но в какой-то момент на рабочем ноуте, где пока что крутится скрипт, начинают завывать вентиляторы - и ресурсы жрет python, а сам скрипт как будто перестает работать.

есть подозрения, что криво написан обработчик входящих данных. идея заключается в том, чтобы находить во входящем потоке три байта, начинающиеся с \n, и сохранять в глобальную переменную второй и третий байты (в боевой версии кода это будет не \n, а 0, а остальные два байта никогда не будут равны 0)

#!/usr/bin/env python
import time, traceback
import logging
import threading
import SocketServer
import datetime 
from threading import Thread
logging.basicConfig()
log = logging.getLogger('logger')
byte1 = 54
byte2 = 56
GPSString = "gps"
class CaaTHandler(SocketServer.StreamRequestHandler):
	def handle_error(self):
		log.error("opachki! oshibka")
	def handle_timeout(self):
		log.error("timeout!!!")
	def handle(self):
		self.request.settimeout(1)
		global byte1
		global byte2
		reading = True
		while reading: 
#			c = self.rfile.read(1)
			c = self.request.recv(1)
			if len(c)!=0:
				print "read %d bytes: %r" % (len(c), c)
				if len(c)!=0:
					print "not empty!"
					if c=="\n":
						log.error("got cr")
						c = self.request.recv(1)
						if len(c)!=0:
							byte1=ord(c)
							log.error("got byte2")
							log.error(c)
							log.error(byte1)
							c = self.request.recv(1)
							if len(c)!=0:
								log.error("got byte2")
								log.error(c)
								byte2=ord(c)
								log.error(byte2)
			if len(c)==0:
				reading = False 
								
class CaaSHandler(SocketServer.StreamRequestHandler):
	def handle(self):
		self.request.settimeout(1)
		while 1: 
			now = datetime.datetime.now()
#		data = self.rfile.readline()
			time.sleep(1)
			self.wfile.write(chr(byte1)+chr(byte2))
			log.error("printing out bytes")
			log.error(byte1)
			log.error(byte2)
#			self.wfile.write(str(now.second)+'\n')

class GPSHandler(SocketServer.StreamRequestHandler):
	def handle(self):
		reading = True
		global GPSString 
		while reading:
		 GPSString = self.rfile.readline() #.rstrip('\r\n')
		 log.error(GPSString)
class MyThread(Thread):
	def __init__(self, name):
		Thread.__init__(self)
		self.name = name
	def run(self):
		server = SocketServer.TCPServer(('', 50007), CaaSHandler)
		server.serve_forever()
		log.error("started service on port 50007")
class MyThread1(Thread):
	def __init__(self, name):
		Thread.__init__(self)
		self.name = name
	def run(self):
		servet = SocketServer.TCPServer(('', 50008), CaaTHandler)
		servet.serve_forever()		
		log.error("started service on port 50008")
class MyGpsListener(Thread): 
	def __init__(self, name):
		Thread.__init__(self)
		self.name = name 
	def run(self): 
		servgps = SocketServer.TCPServer(('',50009), GPSHandler)
		servgps.serve_forever()
		log.error("started service on port 50009")
def create_threads():
	my_thread = MyThread("Sender")
	my_thread.start()
	log.error("started the first thread")
	my_thread1 = MyThread1("Listener")
	my_thread1.start()
	log.error("started the second thread")
	my_thread2 = MyGpsListener("GPSListener")
	my_thread2.start()
	log.error("started the third thread")
if __name__ == "__main__":
		log.error("creating threads")
		create_threads()

планирую запускать все это безобразие на роутере с томато-усб, и не хотелось бы, чтобы оно сжирало ресурсы. строчки с logger и print в финальном скрипте я скорее всего повыключаю. из того, что не нравится: 1. при отключении слушающего устройства (класс CaaS) - при запуске скрипта из терминала в терминал вываливается некий exception (как будто нештатная ситуация), при этом сам скрипт продолжает работать. 2. нет поддержки подключения сразу нескольких клиентов к одному порту. 3. когда рвется соединение к CaaT по таймауту - вроде бы все прекрасно, но если рву соединение подключенным клиентом - ловил подвисания, а в tcpdump какой-то ack пакет нулевой длины, если я правильно интерпретировал увиденное

и еще вопрос: если я запускаю этот скрипт в консоли - как правильно его отключать из этой же консоли (когда там кучка потоков) пока что вышел из положения, сделав из него в макоси сервис и загружаю/выгружаю с помочью launchctl - получается удобнее, чем многочисленные манипуляции с kill

UPD добавил костыль в виде отдельного треда-вочдога. по завершении чтения последнего байта сбрасываю вочдог. со вчерашнего вечера все работает и пока не хоггинга процессора не замечал. broken pipe не починил, но особо и не занимался. как выключать по-быстрому многотредовый скрипт из терминала, если в нем не предусмотрено соответствующих обработчиков - не разобрался. + новая напасть (ну то есть осознал) - после биндинга, когда делаем килл процесса, система не сразу освобождает занятые порты. в итоге перезапустить скрипт получается не сразу. хз как тут быть.



Последнее исправление: puff (всего исправлений: 3)

Тебе нужно наследоваться от ThreadingMixIn чтобы сервер обслуживал нескольких клиентов, так в документации написано.

class XServer(SocketServer.ThreadingMixIn ,SocketServer.TCPServer):
    pass

#и в коде
    servgps = XServer(('', 50009), GPSHandler)
А по поводу трассировок на старте, хорошо бы ошибку видеть.

Yur4eg ★★
()

Чем отличается c ?

...
while reading: 
    c = self.request.recv(1)
...

от

...
log.error("got cr")
c = self.request.recv(1)
if len(c)!=0:
...

И от

...
log.error(byte1)
c = self.request.recv(1)
...

?

ggrn ★★★★★
()
Последнее исправление: ggrn (всего исправлений: 2)
Ответ на: комментарий от itn

а почему нет? у меня там три-пять байт в секунду гоняется (предполагается по гпрс/3г соединению, специально ушел от http запросов)

puff
() автор топика
Ответ на: комментарий от ggrn

просто ничего лучше не придумал, чтобы побайтово считывать из сокета и искать последовательность из /n, byte1, byte2 но похоже тут где-то и ошибся...

puff
() автор топика
Ответ на: комментарий от Yur4eg

про ошибку

[log]Traceback (most recent call last): File «/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py», line 599, in process_request_thread self.finish_request(request, client_address) File «/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py», line 334, in finish_request self.RequestHandlerClass(request, client_address, self) File «/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py», line 657, in __init__ self.finish() File «/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py», line 716, in finish self.wfile.close() File «/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py», line 283, in close self.flush() File «/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py», line 307, in flush self._sock.sendall(view[write_offset:write_offset+buffer_size]) error: [Errno 32] Broken pipe -------------------------------- [/log]

puff
() автор топика
Ответ на: комментарий от puff

теперь какая-то напасть: top | grep ytho ничего не показвает, а при попытке запуска ругается Address already in use на порты 50008 и 50009. а до того вроде бы запускалось. а эту штуку с XServe я проделывал для 50007. странно.

puff
() автор топика
Ответ на: комментарий от Yur4eg

ура!

с несколькими клиентами получилось! спасибо! хз почему там висели открытые порты, но подождал чуть подольше - вроде бы само отвалилось.

а древовидная структура тут на форуме в принципе не предусмотрена

puff
() автор топика
Ответ на: комментарий от ggrn

а. там один if был - какое-то другое условие проверял, потом хотелось поскорее запустить - чтобы не перебивать отступы во всех строчках просто повторил еще один раз if, забыл убрать лишнее, сорри.

log.error - надеялся увидеть это дело в системной консоли, но зря надеялся.

puff
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.