Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 28, 2018 19:44:28

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

Вообще мне нужно, чтобы оно слушало на одном порту хоть по udp входящие пакеты, а потом ретранслировало их клиентам, подключающимся к другому.

но пока что я для простоты ограничился тем, что выдаю клиентам текущее время в секундах.

import time
import SocketServer
import datetime
class CaaSHandler(SocketServer.StreamRequestHandler):
def handle(self):
while 1:
now = datetime.datetime.now()
time.sleep(1)
self.wfile.write(str(now.second)+'\n')

if __name__ == "__main__":
server = SocketServer.TCPServer(('localhost', 50007), CaaSHandler)
server.serve_forever()
пока что вопросы следующие:
1. мне в нынешнем виде не нравится этот sleep. я не проверял с подключением второго клиента (открываю обычным телнетом) - но подозреваю, что со вторым работать уже не будет?
2. плюс не получается завершить сессию телнета - боюсь, когда буду свою софтину сочинять (в смысле не телнетом подключаться) - это будут лишние грабли при ее отключении.

Офлайн

#2 Апрель 29, 2018 09:03:03

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

а зачем здесь нужен sleep ?



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#3 Апрель 29, 2018 12:35:26

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

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

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

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

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

Офлайн

#4 Апрель 29, 2018 22:46:58

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

простенький сервер - вопросы

puff
Вообще мне нужно, чтобы оно слушало на одном порту хоть по udp входящие пакеты, а потом ретранслировало их клиентам, подключающимся к другому.
ЕМНИП это называется чат, и в питоне их полно написано
например
https://github.com/baoboa/pyqt5/blob/master/examples/network/broadcastsender.py

Офлайн

#5 Май 2, 2018 00:10:17

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

там много лишнего, но все равно спасибо.

сейчас другой затык: хочу получить в сокет байты побайтно.

использую такой код:

class CaaTHandler(SocketServer.StreamRequestHandler):
def handle(self):
while 1:
c = self.request.recv(1)
print "read %d bytes: %r" % (len(c), c)

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


ну и еще,
	server = SocketServer.TCPServer(('localhost', 50007), CaaSHandler)
servet = SocketServer.TCPServer(('localhost', 50008), CaaTHandler)
servet.serve_forever()
server.serve_forever()
CaaS - отправляет, CaaT - принимает.
принимать не хотел, пока не поменял местами две последние строчки. и теперь по всей видимости не хочет отправлять. потому что их нужно в отдельных потоках запускать?

Офлайн

#6 Май 2, 2018 01:28:54

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

тэкс.
с потоками разобрался. теперь вопрос другой:

import SocketServer
byte1 = 54
byte2 = 56
byte3 = 13
class CaaSHandler(SocketServer.StreamRequestHandler):
def handle(self):
self.request.settimeout(1)
while 1:
time.sleep(1)
self.wfile.write(chr(byte1)+chr(byte2))
#тут выплевывает 54 и 56


class CaaTHandler(SocketServer.StreamRequestHandler):
def handle(self):
self.request.settimeout(1)
while 1:
c = self.request.recv(1)
if len(c)!=0:
if c=="\n":
print "got cr"
c = self.request.recv(1)
if len(c)!=0:
byte1=c
print "got byte1"
print byte1
c = self.request.recv(1)
if len(c)!=0:
print "got byte2"
byte2=c
print byte3
# тут выводит, якобы все правильно, но при этом первый класс по-прежнему выплевывает старые значения
такое ощущение, что он как один раз в самом начале прочел переменные, так их и не обновляет (а как заставить не из кэша брать, а заново из нормальной памяти читать?)

плюс теперь назрел вопрос: как останавливать в терминале программу, в которой несколько потоков? :-)

Офлайн

#7 Май 2, 2018 12:24:52

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

получилось остановить через ctl+z и потом сделать killall -vs SIGKILL python и kill -TERM и номер. но как-то это неудобно в отладке.

с переменными тоже разобрался вроде бы

теперь остается понять
c = self.request.recv(1)
вот тут c какой тип принимает? я по привычке думал, что байт и есть байт. но оно дальше понимает
if c==“\n”:

но не понимает
if c==13:
(проверял и с 10)

и как читать в бинарном виде?

Отредактировано puff (Май 2, 2018 12:32:19)

Офлайн

#8 Май 2, 2018 16:40:04

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

теперь пытаюсь побороть, чтобы оно несколько соединений воспринимало.
нарыл код на реддите, но чото не понял

import socket
import select
import datetime
import time
from time import sleep

server = socket.socket()
server.bind(('localhost', 50009))
server.listen(10)

clients = set()
while True:
# Here, the OS will notify you at some time in the future, when at
# least one socket is ready to be read from or written to (it will
# also tell you sockets which experience errors).
#
# Note that a 'read' on the server is equivalent to a connection.
readers, writers, errors = select.select([server] + list(clients), [], [])

for sock in readers:
if sock == server:
client, _ = server.accept()
clients.add(client)
print "client added?"
# now = datetime.datetime.now()
# sock.sendall(str(now.second)+"\n")
# time.sleep(0.5)
else:
# (I'm going to use a bigger buffer, just because it can be
# more efficient, depending on how much data you're tranporting)
try:
#data = sock.read(1024)
now = datetime.datetime.now()
sock.sendall(str(now.second)+"\n")
time.sleep(0.5)
except (OSError, socket.error) as err:
# There are lots of socket-related errors in 3.x, but this
# should cover the majority of cases in 2.x
print err
#data = None

#if not data:
# clients.remove(sock)
# sock.close()

#print data
# Note that I avoid sleeping here, since select() will sleep
# when no data is available
оно начинает пулять не сразу, а только когда я в телнете нажму энтер. как добиться того, чтобы сразу пуляло?
там на реддите изнчально чувак делал сразу по тысяче потоков, и ему предложили воспльзоваться этим.
он отдельно делал и сервер (который слушает), и клиент (который отправляет)
я вот не пойму, этот код, что я раскуриваю - он сразу и за серверную и за клиентскую часть?(clients.add() намекает)? и что тогда в else происходит (в котором я собственно начинаю выводить секунды) - чертовщина какая-то.

Офлайн

#9 Май 3, 2018 23:43:03

puff
Зарегистрирован: 2018-04-28
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

простенький сервер - вопросы

Пока что отложил это дело с несколькими подключениями. Такой вопрос:
сейчас код, который принимает байты, выглядит следующим образом:

import time, traceback
import threading
import SocketServer
import datetime
from threading import Thread
byte1 = 54
byte2 = 56
class CaaTHandler(SocketServer.StreamRequestHandler):
def handle(self):
self.request.settimeout(1)
global byte1
global byte2
while 1:
# 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":
print "got cr"
c = self.request.recv(1)
if len(c)!=0:
byte1=ord(c)
print "got byte2"
print c
print byte1
c = self.request.recv(1)
if len(c)!=0:
print "got byte2"
print c
byte2=ord(c)
print byte2
оно все отлично работает, если туда стучать через телнет или через неткат. принимает байты, обновляет, нормально закрывается и все такое. и реальный таймаут 1 с - выкидывает после бездейтсвия.

но когда начал делать приложение для андроида - у меня вдруг все стало плохо: питон стал загружать процессор, скрипт не работает, во всяком случае на прием. очевидно, что андроид как-то некорректно завершает программу (я в дебаге его запускаю и в дебаге же останавливаю, там некий сервис крутится)
попробовал посмотреть с помощью tcpdump и вот какие получились последние три секунды:
192.168.1.18.50008 > 192.168.1.101.40073: Flags , cksum 0x3da4 (correct), seq 1, ack 22, win 4097, options , length 0
23:24:08.654737 IP (tos 0x0, ttl 64, id 20273, offset 0, flags , proto TCP (6), length 55)
192.168.1.101.40073 > 192.168.1.18.50008: Flags , cksum 0x3698 (correct), seq 22:25, ack 1, win 58, options , length 3
23:24:08.654798 IP (tos 0x0, ttl 64, id 59531, offset 0, flags , proto TCP (6), length 52)
192.168.1.18.50008 > 192.168.1.101.40073: Flags , cksum 0x6782 (correct), seq 1, ack 25, win 4097, options , length 0
23:24:09.354462 IP (tos 0x0, ttl 64, id 20274, offset 0, flags , proto TCP (6), length 55)
192.168.1.101.40073 > 192.168.1.18.50008: Flags , cksum 0x34c1 (correct), seq 25:28, ack 1, win 58, options , length 3
23:24:09.354489 IP (tos 0x0, ttl 64, id 31043, offset 0, flags , proto TCP (6), length 52)
192.168.1.18.50008 > 192.168.1.101.40073: Flags , cksum 0x6503 (correct), seq 1, ack 28, win 4096, options , length 0
23:24:10.059348 IP (tos 0x0, ttl 64, id 20275, offset 0, flags , proto TCP (6), length 55)
192.168.1.101.40073 > 192.168.1.18.50008: Flags , cksum 0x3241 (correct), seq 28:31, ack 1, win 58, options , length 3
23:24:10.059373 IP (tos 0x0, ttl 64, id 3498, offset 0, flags , proto TCP (6), length 52)
192.168.1.18.50008 > 192.168.1.101.40073: Flags , cksum 0x628a (correct), seq 1, ack 31, win 4096, options , length 0
23:24:10.480374 IP (tos 0x0, ttl 64, id 20276, offset 0, flags , proto TCP (6), length 52)
192.168.1.101.40073 > 192.168.1.18.50008: Flags , cksum 0x7224 (correct), seq 31, ack 1, win 58, options , length 0
23:24:10.480411 IP (tos 0x0, ttl 64, id 52254, offset 0, flags , proto TCP (6), length 52)
192.168.1.18.50008 > 192.168.1.101.40073: Flags , cksum 0x611a (correct), seq 1, ack 32, win 4096, options , length 0
(101 - андроид, 18 - комп)
от андроида каким-то образом пришел запрос с нулевой длиной. флаг F. (кстати, что это?)
и вроде питон отправляет обчный акнолежмент.
как понять, чем отличается то, что я пишу в сокет вручную (через телнет), от того, что я пишу из андроида?
можно ли в коде питона что-то подкрутить, чтобы вот так нагло не зависало?

Отредактировано puff (Май 3, 2018 23:43:38)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version