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

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

Войти через центр авторизации
Похожие вопросы
deeplay Новосибирск
от 130 000 ₽
от 130 000 ₽
Enjoy PRO Санкт-Петербург
от 140 000 до 180 000 ₽
24 окт. 2020, в 22:43
3000 руб./за проект
24 окт. 2020, в 22:27
2500 руб./за проект