@KorwinD

Как решить проблему с использованием сокетов в python?

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

Пример:
Server: Server to Client reporting2373896/home/corwin/Документы/NoCloud/

Это три склеенных вместе запроса.

Ниже код программ.
import socket
import os

def open_server():
    host = '0.0.0.0'
    port = 9091
    serv_addr = (host, port)

    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    tcp_socket.bind(serv_addr)
    tcp_socket.listen(1)

    print('Waiting connection')

    connection(tcp_socket)

def connection(tcp_socket):
    conn, clnt_addr = tcp_socket.accept()
    print('Connection is established')

    data_to_recv = conn.recv(1024)
    if not data_to_recv:
        conn.close()
        tcp_socket.close()
        sys.exit(1)
    else:
        print('Client: '+data_to_recv)
        conn.send(b'Server to Client reporting') #Первый раз отсылаю информацию.

    transerf(conn, tcp_socket)

def transerf(conn, tcp_socket):
    conn.send(str(os.path.getsize(os.path.dirname(__file__)+'list.dat'))) #Второй раз отсылаю информацию.
    fl = open(os.path.dirname(__file__)+'list.dat', 'rb')
    st = fl.read()
    conn.send(st) #Третий раз отсылаю информацию.
    conn.close()
    tcp_socket.close()

def server():
    open_server()

server()


import socket
import os

def connection():
    serv_addr = ('127.0.0.1', 9091)
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_socket.connect(serv_addr)
    print('Connection is established')

    tcp_socket.send(b'Client to Server reporting')

    data_to_recv = tcp_socket.recv(1024) #Получаю первый запрос.
    print('Server: '+data_to_recv)

    transerf(tcp_socket)

def transerf(tcp_socket):
    size = tcp_socket.recv(1024) #Второй раз получаю запрос.
    data = tcp_socket.recv(int(size)) #Третий раз получаю запрос.
    fl = open(os.path.dirname(__file__)+'list1.dat', 'w')
    fl.write(data)
    tcp_socket.close()

def client():
    connection()

client()
  • Вопрос задан
  • 3192 просмотра
Пригласить эксперта
Ответы на вопрос 2
@nirvimel
Я понял в чем суть проблемы только по одному описанию, еще не успев заглянуть в код (редко такое происходит). Вы понимаете в чем смысл единственного параметра у recv? Для чего вы передаете туда константу 1024? Это объем в байтах, который читается из сокета за один вызов. Сокет - это не очередь передаваемых пакетов, а поток байт, который наполняется с одной стороны через send и вычерпывается с другой через recv (флаг socket.SOCK_STREAM символизирует это). Если в некоторых случаях recv возвращает в точности тот же пакет фрагмент данных, который был передан за один вызов send, то только потому, что в потоке в этот момент нет других данных.
Следовательно, если логика вашего клиент-сервера подразумевает обмен пакетами, то всю разбивку на пакеты вы должны реализовывать самостоятельно. Например, в заголовке каждого пакета передавать его длину, а после прочтения этого заголовка, читать из сокета ровно заданное количество байт.
Все это издержки работы с голым TCP. Для решения как раз этих проблем и существуют специальные пакетные протоколы и библиотеки для работы с ними. Можете попробовать, например, ZeroMQ (через PyZMQ), если вас интересует именно обмен пакетами ( то есть "сообщениями" в терминах ZeroMQ) и нет желания писать этот велосипед самостоятельно.
Ответ написан
Комментировать
@lega
Они не только могут склеиваться, но и разрываться в разных местах, например отправили 3 раза, получили 5 раз.
В обычном http для этого создают отдельное подключение для отдельной передачи (одного файла).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы