Я скопировал пример echo server из документации python, и он работает нормально. Но когда я редактирую код, чтобы он не отправлял данные обратно клиенту, метод socket.recv() не возвращает результат при повторном вызове.
import socket
HOST = '' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1)
whileTrue: data = conn.recv(1024) ifnot data: break conn.sendall(b'ok') conn.close()
В исходной версии из документации python цикл while немного отличается:
whileTrue: data = conn.recv(1024) ifnot data: break conn.sendall(data)
Код клиента:
import socket
HOST = 'localhost' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall(b'Hello, world') data = s.recv(1024) s.close() print('Received', repr(data))
Переведено автоматически
Ответ 1
Сокеты TCP - это потоки данных. Нет однозначной корреляции между вызовами отправки с одной стороны и приема вызовов с другой. Существует корреляция более высокого уровня, основанная на протоколе, который вы реализуете. В исходном коде было правило, что сервер будет отправлять именно то, что он получил, пока клиент не закроет входящую сторону соединения. Затем сервер закрыл сокет.
С вашим изменением правила изменились. Теперь сервер продолжает получать и отбрасывать данные до тех пор, пока клиент не закроет входящую сторону соединения. Затем сервер отправляет "ok" и закрывает сокет.
Клиент, использующий первое правило, зависает, потому что он ожидает данных до того, как закроет сокет. Если он хочет работать с этим новым правилом сервера, он должен закрыть исходящую часть сокета, чтобы сообщить серверу, что все готово, и тогда он может получить возвращаемые данные.
Я обновил клиент и сервер, чтобы они отключали части соединения, а также попросил клиента выполнить несколько повторных запросов на случай, если входящие данные фрагментированы. Менее полные реализации, похоже, работают для небольших полезных нагрузок, потому что вы вряд ли получите фрагментацию, но ужасно ломаются в реальном производственном коде.
сервер
import socket
HOST = '' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(1)
whileTrue: data = conn.recv(1024) ifnot data: break conn.sendall(b'ok') conn.shutdown(socket.SHUT_WR) conn.close()
клиент
import socket
HOST = 'localhost' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall(b'Hello, world') s.shutdown(socket.SHUT_WR) data = b'' whileTrue: buf = s.recv(1024) ifnot buf: break data += buf s.close() print('Received', repr(data))
Ответ 2
Количество операций приема и отправки должно совпадать, потому что они блокируют. Это блок-схема для вашего кода:
Server listen Client connect Server receive (this waits until a message arrives at the server) [1] Client send 'Hello world' (received by [1]) Server receive (because there was data received) [2] Client receive [3]
Поскольку сервер и клиент сейчас заблокированы, ни одна программа не может продолжать работу дальше.
Исправление заключалось бы в удалении вызова приема клиента, потому что вы удалили вызов отправки сервера.