#python #sockets
#python #сокеты
Вопрос:
В моей локальной сети прослушивается следующий сокет:
def recvall(sock):
BUFF_SIZE = 4096 # 4 KiB
fragments = []
while True:
chunk = sock.recv(BUFF_SIZE)
fragments.append(chunk)
# if the following line is removed, data is omitted
time.sleep(0.005)
if len(chunk) < BUFF_SIZE:
break
data = b''.join(fragments)
return data
def main():
pcd = o3d.geometry.PointCloud()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.0.22', 2525))
print("starting listening...")
s.listen(1)
counter = 0
while True:
clientsocket, address = s.accept()
print(f"Connection from {address} has been established!")
received_data = recvall(clientsocket)
clientsocket.send(bytes(f"response nr {counter}!", "utf-8"))
counter = 1
print(len(received_data))
if __name__ == "__main__":
main()
На этот порт я отправляю байтовые данные длиной 172800
в байты из приложения на моем мобильном телефоне.
Как можно видеть, я печатаю объем полученных данных. Количество будет правильным, только если я использую time.sleep()
, как показано в приведенном выше коде. Если я не использую этот метод, принимается только часть данных.
Очевидно, что это некоторая проблема с синхронизацией, вопрос в следующем: как я могу быть уверен, что все данные будут постоянно получать без использования time.sleep()
(поскольку это также не на 100% точно работает, в зависимости от установленного времени ожидания)
Ответ №1:
sock.recv()
возвращает доступные данные. Соответствующая часть справочной страницы recv(2)
:
The receive calls normally return any data available, up to the requested amount,
rather than waiting for receipt of the full amount requested.
В вашем случае, time.sleep(0.005)
похоже, все оставшиеся данные сообщения поступают и сохраняются в буфере.
Есть несколько вариантов, которые устраняют необходимость time.sleep(0.005)
. Какой из них является наиболее подходящим, зависит от ваших потребностей.
- Если отправитель отправляет данные, но не ожидает ответа, вы можете попросить отправителя закрыть сокет после отправки данных, т. Е.
sock.close()
Послеsock.sendall()
.recv()
вернет пустую строку, которую можно использовать для выхода изwhile
цикла на приемнике.
def recvall(sock):
BUFF_SIZE = 4096
fragments = []
while True:
chunk = sock.recv(BUFF_SIZE)
if not chunk:
break
fragments.append(chunk)
return b''.join(fragments)
- Если отправитель отправляет сообщения фиксированной длины, например,
172800
байты, вы можете использоватьrecv()
в цикле, пока получатель не получит все сообщение.
def recvall(sock, length=172800):
fragments = []
while length:
chunk = sock.recv(length)
if not chunk:
raise EOFError('socket closed')
length -= len(chunk)
fragments.append(chunk)
return b''.join(fragments)
- Другие варианты включают в себя: a. добавление разделителя, например, специального символа, который не может быть частью данных, в конце сообщений, которые отправляет отправитель; затем получатель может работать
recv()
в цикле, пока не обнаружит разделитель и b. добавление к сообщениям отправителя префикса их длины;затем получатель будет знать, сколько байтов ожидать для каждого сообщения.