Современный мир завязан на системах связи, когда различные устройства «общаются» между собой посредством «правил», или протоколов модели OSI (Open Systems Interconnection model), определяющей методы взаимодействия. В тексте рассмотрим два самых популярных протокола транспортного уровня — TCP и UDP — и сравним их.
Прежде всего напомним, что такое сетевые протоколы. Сетевые протоколы — это правила взаимодействия устройств в сети, благодаря которым различные девайсы могут работать друг с другом, несмотря на конструктивные различия. На транспортном уровне происходит прием данных с сетевого уровня и передача их на сеансовый уровень.
Первым из рассматриваемых протоколов будет TCP, или Transmission Control Protocol, который используется для транспортировки сообщений между устройствами в сети.
В сети файлы не передаются целиком, а дробятся и передаются в виде относительно небольших сообщений. Далее они передаются другому устройству — получателю, где повторно собираются в файл.
Например, человек хочет скачать картинку. Сервер обрабатывает запрос и высылает в ответ требуемое изображение. Ему, в свою очередь, необходим путь или канал, по которому он будет передавать информацию. Поэтому сервер обращается к сетевому сокету для установки требуемого соединения и отправки картинки. Сервер дробит данные, инкапсулирует их в блоки, которые передаются на уровень TCP получателя при помощи IP-протокола. Далее получатель подтверждает факт передачи.
У протокола TCP есть несколько особенностей:
Протокол TCP гарантирует доставку, а также обеспечивает целостность данных, передаваемых в сети. Поэтому он применяется для передачи данных, которые чувствительны к нарушению целостности, — например, текстов, файлов и т.п. Вот несколько протоколов, которые работают по TCP:
Эти примеры работают на уровне приложений стека TCP/IP и передают данные вниз к TCP, на транспортный уровень.
В каждый пакет данных TCP добавляет заголовок общим объемом в 20 байт (или октетов), в котором содержатся 10 обязательных полей:
TCP используется при передаче данных в таких протоколах, как HTTP, Telnet, FTP, SMTP. При использовании протокола нужно учесть, что при увеличении потери пакетов время, затрачиваемое на доставку файла, увеличивается.
Чтобы достичь максимальной пропускной способности TCP-соединения, можно выполнить следующие шаги:
Увеличить размер окна. Размер окна, или TCP Window Size, — это количество данных, которое может быть передано в данный момент без подтверждения. Это значение устанавливается в начале соединения между устройствами. Однако это значение можно изменить заранее, введя команду regedit в поиске и перейдя по следующему пути:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters\DefaultSendWindow
Увеличение параметра приведет к тому, что уменьшится количество проверок полученных данных и увеличится эффективность использования полосы пропускания. Также, перейдя по пути:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters
, можно добавить значение Tcp1323Opts, которое отвечает за изменение размера окна и управление временной меткой.
Изменение значения SackOpts. SACK, или селективное подтверждение, крайне важно для подключений с большим размером окна. Без этой функции проверка полученных данных выполняется только по последнему номеру последовательности полученных данных. Но с включением этой функции появляется возможность подтверждать получение отдельных блоков. Чтобы изменить данный параметр, можно перейти по пути:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
и выбрать параметр SackOpts.
Изменение значения TcpMaxDupAcks. Данный параметр отвечает за количество полученных подтверждений о передаче. Стандартное значение состоит из одного подтверждения и двух дубликатов. Параметр можно изменить, перейдя по пути:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
и выбрав TcpMaxDupAcks. Это позволит вам назначать количество требуемых подтверждений для запуска быстрой повторной передачи, что в результате скажется на скорости передачи данных.
Стоит отметить, что данными манипуляциями выигрываются доли секунд, поэтому сильно прироста скорости вы не увидите.
Если нам очень важна скорость передачи, а вот потеря пакетов не так критична (как, например, в голосовом или видеотрафике), то лучше использовать UDP, или User Datagram Protocol. В отличие от TCP он обеспечивает передачу данных без получения подтверждения от пользователя. Проще говоря, просто отправляет пакеты и не ждет ничего в ответ. Из-за этого достигается высокая скорость в ущерб надежности.
Чаще всего UDP применяется в чувствительных ко времени службах, где потерять пакеты лучше, чем ждать. Звонки в Skype или Google Meet, стриминг видео, онлайн-трансляции используют этот протокол из-за того, что они чувствительны ко времени и рассчитаны на определенный уровень потерь. Вся голосовая связь через интернет работает по протоколу UDP. Также UDP очень часто используется в онлайн-играх. Аналогичная история с DNS-серверами, поскольку они должны быть быстрыми и эффективными.
Примерами протоколов, использующих UDP-протокол, являются:
Ключевым различием между TCP и UDP является скорость, поскольку TCP сравнительно медленнее UDP. В целом, UDP является быстрым, простым и эффективным протоколом, однако повторная передача потерянных пакетов данных возможна только в TCP.
Еще одно заметное различие между TCP и UDP заключается в том, что первый обеспечивает упорядоченную доставку данных от пользователя к серверу (и наоборот). UDP, в свою очередь, не проверяет готовность получателя и может доставлять пакеты вразнобой.
Рассмотрим разницу характеристик протоколов TCP и UDP.
TCP | UDP | |
Состояние соединения | Требуется установленное соединение для передачи данных (соединение должно быть закрыто после завершения передачи) | Протокол без соединения, без требований к открытию, поддержанию или прерыванию соединения |
Гарантия доставки | Может гарантировать доставку данных получателю | Не гарантирует доставку данных получателю |
Повторная передача данных | Повторная передача нескольких кадров в случае потери одного из них | Отсутствие повторной передачи потерянных пакетов |
Проверка ошибок | Полная проверка ошибок | Базовый механизм проверки ошибок. Использует вышестоящие протоколы для проверки целостности |
Метод передачи | Данные считываются как поток байтов; сообщения передаются по границам сегментов | UDP-пакеты с определенными границами; отправляются по отдельности и проверяются на целостность по прибытии |
Сферы применения | Используется для передачи сообщений электронной почты, HTML-страниц браузеров | Видеоконференции, потоковое вещание, DNS, VoIP, IPTV |
Также нередко возникает вопрос, касающийся использования данных протоколов при VPN-соединениях. К примеру, в OpenVPN существует возможность выбора между TCP- и UDP-протоколами.
Условимся, что VPN заворачивает передаваемые данные в еще один протокол (на самом деле все намного сложнее). Если ваш VPN-туннель использует в качестве транспортного протокола TCP, то передача данных по UDP-протоколу теряет свои преимущества. Как минимум на определенном участке пути. Поэтому для VPN-туннеля советуют использовать UDP-протокол, ведь TCP будет штатно работать внутри UDP-туннеля.
Более 100 готовых к работе конфигураций.
Выбрать
Каждый протокол хорош под свои задачи, недаром они являются одними из самых распространенных в интернете. В завершение сравнения TCP и UDP можно выделить, что TCP применяется там, где важно доставить все данные в определенном порядке. Зона применения UDP, в свою очередь, — это голосовой и видеотрафик, где доставка всех пакетов не является обязательной.
Также серьезным отличием TCP от UDP является размер заголовков. У TCP он составляет 20-60 байт, а у UDP — всего 8 байт. Это показывает, насколько сложнее устроен протокол TCP, ведь он приоритизирует трафик и проверяет блоки данных на наличие ошибок.
Имя | Описательное имя входного коннектора, используемое для справки в GeoEvent Manager. |
Пространственная привязка по умолчанию | Известный идентификатор (WKID) пространственной привязки, используемый при построении геометрии из значений полей атрибутов, координаты которых не являются значениями широты и долготы для предполагаемой географической системы координат WGS84, или строки геометрии, не включающие пространственную привязку. Также может быть указано известное текстовое значение (WKT) или имя поля атрибута, содержащего WKID или WKT. |
Порт сервера | Порт сервера, используемый при установке сокета UDP. Клиенты UDP должны иметь возможность обнаруживать и подключаться к этому порту. По умолчанию используется порт 5000, но можно использовать любой доступный порт сервера. |
Прикрепить исходный IP к сообщению | Указывает, должен ли транспорт добавлять IP-адрес компьютера, отправившего дейтаграмму UDP к дейтаграмме (сообщению). Если указанное свойство Символ префикса IP источника совпадает с Разделителем атрибутов, адаптер будет интерпретировать добавленные значение IP и порт как дополнительное строковое значение атрибута. Убедитесь, что Определение GeoEvent содержит поле атрибута для размещения данных, добавляемых к каждой дейтаграмме.
|
Символ-префикс исходного IP (Условия) | Один буквенный символ, используемый транспортом для разделения IP-адреса и номера порта, добавляемых к каждой датаграмме UDP. Обычно используется тот же символ, что и Разделитель атрибутов для значений основного атрибута сообщения, поэтому IP-адрес и порт добавляются в качестве нового атрибута, однако значения IP-адреса и порта могут быть присоединены к конечному строковому значению с помощью другого разделителя. Это свойство отображается, когда для параметра Прикрепить исходный IP к сообщению задано значение Да, и скрыто, когда параметр Прикрепить исходный IP к определению сообщения настроен как Нет. |
Символы для прикрепления к каждому сообщению | Один буквенный символ, который транспорт добавит к каждой дейтаграмме UDP, прежде чем необработанный массив байтов сообщения будет отправлен адаптеру. UDP-дейтаграммы обычно являются компактными сообщениями; клиентские приложения могут не включать разделитель между сообщениями. Однако адаптеру требуется Разделитель сообщений для указания конца записи данных события, поэтому, если передающий UDP-клиент не включает разделитель сообщений, укажите его с помощью этого свойства. |
Размер буфера (байты) | Задает размер буфера, выделяемого транспортом для хранения необработанных байтов, полученных из передающего клиентского приложения UDP. Значение по умолчанию – 2048 байт. Буфер должен быть достаточно большим для размещения IP-заголовков, заголовков UDP, значений атрибутивных данных, строковых представлений геометрии, принимаемых в качестве данных, и любых данных, добавляемых к каждому полученному сообщению. |
Разделитель сообщений | Один буквенный символ, который указывает на конец записи данных событий. Значения Unicode могут применяться для указания разделителя символов. Этот символ не должен заключаться в кавычки. Новая строка (\n) является часто используемым разделителем конца записи. |
Разделитель атрибутов | Один буквенный символ, используемый для отделения одного значения атрибута от другого в сообщении. Значения Unicode могут применяться для указания разделителя символов. Этот символ не должен заключаться в кавычки. Запятая (,) – общий разделитель атрибутов |
Входящие данные содержат определение GeoEvent | Указывает, следует ли использовать первое значение атрибута каждой строки текста с разделителями в качестве имени определения GeoEvent. Дополнительные сведения см. в примечаниях к использованию выше.
|
Создать определения неопознанных событий (Условия) | Указывает, следует ли создавать новое Определение GeoEvent, если определение с указанным именем не существует. Если текстовый файл с разделителями содержит записи событий от различных типов датчиков, для указания типа события используется первое значение атрибута, которое берется в качестве имени определения GeoEvent.
Это свойство показывается, когда для Входящие данные содержат определение GeoEvent задано значение Да, и скрыто, если выбрано значение Нет |
Создавать определение GeoEvent (Условия) | Указывает, следует ли использовать новое или существующее Определение GeoEvent для данных входящих событий. Определение GeoEvent требуется для GeoEvent Server для понимания полей атрибутов и типов данных входящих событий.
Это свойство показывается, когда для Входящие данные содержат определение GeoEvent задано значение Нет, и скрыто, если выбрано значение Да |
Имя определения GeoEvent (новое) (Условия) | Имя, которое присваивается для нового Определения GeoEvent. Если определение GeoEvent с указанным именем уже существует, будет использоваться существующее определение GeoEvent. Первая полученная запись данных будет использоваться для определения ожидаемой схемы последующих записей данных, на основе которой будет создано новое определение GeoEvent. Это свойство показывается, когда для свойства Создать определение GeoEvent задано значение Да, и скрыто, если выбрано значение Нет |
Имя определения GeoEvent (существующее) (Условия) | Имя существующего определения GeoEvent для использования при адаптации полученных данных для создания данных событий для обработки сервисом GeoEvent. Это свойство показывается, когда для свойства Создать определение GeoEvent задано значение Нет, и скрыто, если выбрано значение Да |
Построить геометрию из полей | Указывает, должен ли входной коннектор создавать геометрию точки, используя значения координат, полученные в качестве атрибутов. По умолчанию – Нет.
|
Поле геометрии X (Условия) | Поле атрибута в данных входящего события, содержащее координатную часть X (например, горизонталь или долготу) местоположения точки. Это свойство показывается, когда для Построить геометрию из полей задано значение Да, и скрыто, если выбрано значение Нет |
Поле геометрии Y (Условия) | Поле атрибута в данных входящего события, содержащее координатную часть Y (например, вертикаль или широту) местоположения точки. Это свойство показывается, когда для Построить геометрию из полей задано значение Да, и скрыто, если выбрано значение Нет |
Поле геометрии Z (Условия) | Имя поля в данных входящего события, содержащего координатную часть Z (например, глубина или высота) местоположения точки. Если оставить пустым, значение Z будет опущено и будет построена 2D геометрия точки. Это свойство показывается, когда для Построить геометрию из полей задано значение Да, и скрыто, если выбрано значение Нет |
Ожидаемый формат данных | Шаблон, используемый для соответствия ожидаемым строковым представлениям значений даты / времени и преобразования их в значения даты Java. Формат шаблона следует нормам для класса Java SimpleDateFormat. Это свойство не имеет значения по умолчанию. GeoEvent Server предпочитает, чтобы значения даты/времени выражались в стандарте ISO 8601, но несколько строковых представлений значений даты/времени, обычно распознаваемых как значения даты, могут быть преобразованы в значения даты Java без указания Ожидаемого формата даты. В том числе:
Если полученные значения даты/времени выражены с помощью формата, отличного от одного из пяти, показанных выше, необходимо указать Ожидаемый формат даты, чтобы GeoEvent Server знал, как следует адаптировать значения даты/времени. |
Язык форматирования чисел | Идентификатор локали (ID), используемый для чувствительного к локали поведения при форматировании чисел из значений данных. По умолчанию используется локаль компьютера, на котором установлен GeoEvent Server. Дополнительные сведения см. в разделе Поддерживаемые локали Java. |
Режим мультикаст | Указывает, должен ли входной коннектор присоединяться к группе мультикаст для получения сообщений, маршрутизируемых внутренней сетью группе предполагаемых получателей. По умолчанию – Нет.
|
Группа мультикаст (Условия) | Введите адрес группы, к которой присоединится входной коннектор в режиме мультикаст. Входной коннектор будет получать пакеты, отправленные на этот адрес группы. Диапазон IP-адресов 239.x.x.x зарезервирован RFC 2365 для специального использования администратором организации в пределах одной локальной сети. Это свойство показывается, когда для свойства Режим мультикаст задано значение Да, и скрыто, если выбрано значение Нет |
Протокол пользовательских дейтаграмм (UDP) работает иначе, чем TCP/IP. Где TCP — это протокол , ориентированный на потоки , гарантирующий, что все данные передается в правильном порядке, UDP представляет собой протокол , ориентированный на сообщения . UDP не требует долговременного соединения, поэтому настройка UDP розетка немного проще. С другой стороны, сообщения UDP должны соответствовать в одном пакете (для IPv4 это означает, что они могут содержать только 65 507 байтов, потому что пакет размером 65 535 байт также включает информацию заголовка) и доставка не гарантируется, как с TCP.
Поскольку соединение отсутствует, серверу не нужно слушать и принимать соединения. Нужно только использовать bind() чтобы связать его сокет с портом, а затем дождаться индивидуального Сообщения.
импортный разъем импорт системы # Создаем сокет TCP/IP носок = сокет.сокет (сокет.AF_INET, сокет.SOCK_DGRAM) # Привязать сокет к порту server_address = ('localhost', 10000) print >>sys.stderr, 'запуск на %s, порт %s' % server_address sock.bind (адрес_сервера)
Сообщения считываются из сокета с помощью функции recvfrom(), которая возвращает данные, а также адрес клиента, с которого было отправлено.
пока верно: print >>sys. stderr, '\nожидание получения сообщения' данные, адрес = sock.recvfrom(4096) print >>sys.stderr, 'получено %s байт от %s' % (len(data), адрес) печать >>sys.stderr, данные если данные: отправлено = sock.sendto (данные, адрес) print >>sys.stderr, 'отправлено %s байт обратно на %s' % (отправлено, адрес)
Эхо-клиент UDP подобен серверу, но не использует bind() для присоединения своего сокета к адресу. Оно использует sendto() для доставки своего сообщения непосредственно на сервер, и recvfrom() для получения ответа.
импортный разъем импорт системы # Создаем UDP-сокет носок = сокет.сокет (сокет.AF_INET, сокет.SOCK_DGRAM) server_address = ('localhost', 10000) message = 'Это сообщение. Это будет повторяться». пытаться: # Отправить данные print >>sys.stderr, 'отправка сообщения "%s"' % отправлено = sock.sendto (сообщение, адрес_сервера) # Получить ответ print >>sys.stderr, 'ожидание получения' данные, сервер = sock. recvfrom(4096) print >>sys.stderr, 'получено "%s"' % данных окончательно: print >>sys.stderr, 'закрытие сокета' носок.закрыть()
Запуск сервера производит:
$ python ./socket_echo_server_dgram.py запуск на локальном хосте, порт 10000 ожидание получения сообщения получено 42 байта от ('127.0.0.1', 50139) Это сообщение. Это будет повторяться. отправил 42 байта обратно на ('127.0.0.1', 50139) ожидание получения сообщения
и вывод клиента:
$ питон ./socket_echo_client_dgram.py отправка «Это сообщение. Оно будет повторено». ожидание получения получено "Это сообщение. Оно будет повторено." закрытие сокета $
У меня есть Ethernet-трафик UDP, который я хочу получать на машину (192.168.2.2:7800) (исходящую с отдельной машины (192.168.2.12)).
Я вижу, что данные передаются на принимающую машину, выполнив дамп TCP:
tcpdump -n -i enp5s0f1 udp порт 7800 tcpdump: подробный вывод подавлен, используйте -v или -vv для полного декодирования протокола прослушивание на enp5s0f1, тип канала EN10MB (Ethernet), размер захвата 262144 байт 19:04:13. 160763 IP 192.168.2.12.ovbus > 192.168.2.2.asr: UDP, длина 1052 19:04:13.170854 IP 192.168.2.12.ovbus > 192.168.2.2.asr: UDP, длина 1052
Я попытался настроить UDP-сервер Python с IP-адресом 192.168.2.2 и портом 7800, используя следующий код, который я получил здесь от Радослава Матусяка (https://github.com/rsc-dev/pyproxy/blob /master/code/pyproxy.py):
#!/usr/bin/env Python __author__ = 'Радослав Матусяк' __copyright__ = 'Авторское право (c) 2016 Радослав Матусяк' __license__ = 'MIT' __версия__ = '0.1' """ TCP/UDP-прокси. """ импортировать аргументы сигнал импорта журнал импорта импортировать выбрать импортный сокет FORMAT = '%(asctime)-15s %(levelname)-10s %(сообщение)s' logging.basicConfig(формат=ФОРМАТ) РЕГИСТРАТОР = logging.getLogger() LOCAL_DATA_HANDLER = лямбда x:x REMOTE_DATA_HANDLER = лямбда x:x BUFFER_SIZE = 2 ** 10 # 1024. Сохранить размер буфера как степень 2. Def udp_proxy (источник, dst): """Запустите UDP-прокси. Аргументы: src -- исходный IP-адрес и строка порта.То есть: "127.0.0.1:8000" dst -- IP-адрес и порт назначения. То есть: "127.0.0.1:8888" """ LOGGER.debug('Запуск UDP-прокси...') LOGGER.debug('Источник: {}'.format(src)) LOGGER.debug('Dst: {}'.format(dst)) proxy_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) proxy_socket.bind (ip_to_tuple (источник)) client_address = Нет server_address = ip_to_tuple(dst) LOGGER.debug('Зацикливание прокси (нажмите Ctrl-Break, чтобы остановить)...') пока верно: данные, адрес = proxy_socket.recvfrom(BUFFER_SIZE) LOGGER.debug('Данные получены') если client_address == None: client_address = адрес если адрес == client_address: данные = LOCAL_DATA_HANDLER (данные) proxy_socket.sendto (данные, server_address) адрес elif == адрес_сервера: данные = REMOTE_DATA_HANDLER (данные) proxy_socket.sendto (данные, client_address) client_address = Нет еще: LOGGER. warning('Неизвестный адрес: {}'.format(str(адрес))) # конец функции udp_proxy защита tcp_proxy (источник, dst): """Запустить TCP-прокси. Аргументы: src -- исходный IP-адрес и строка порта. То есть: "127.0.0.1:8000" dst -- IP-адрес и порт назначения. То есть: "127.0.0.1:8888" """ LOGGER.debug('Запуск TCP-прокси...') LOGGER.debug('Источник: {}'.format(src)) LOGGER.debug('Dst: {}'.format(dst)) сокеты = [] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind (ip_to_tuple (источник)) s.слушай(1) s_src, _ = s.accept() s_dst = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s_dst.connect(ip_to_tuple(dst)) sockets.append(s_src) sockets.append(s_dst) пока верно: s_read, _, _ = select.select(сокеты, [], []) для s в s_read: данные = s.recv (BUFFER_SIZE) если s == s_src: d = LOCAL_DATA_HANDLER(данные) s_dst. sendall (д) Элиф с == s_dst: d = REMOTE_DATA_HANDLER (данные) s_src.sendall (д) # конец функции tcp_proxy определение ip_to_tuple (ip): """Разобрать строку IP и вернуть кортеж (ip, port). Аргументы: ip -- IP-адрес: строка порта. То есть: «127.0.0.1:8000». """ ip, порт = ip.split(':') вернуть (ip, int(порт)) # конец функции ip_to_tuple деф основной(): """Основной метод.""" parser = argparse.ArgumentParser(description='TCP/UPD proxy.') # группы TCP UPD proto_group = parser.add_mutually_exclusive_group (обязательно = True) proto_group.add_argument('--tcp', action='store_true', help='TCP proxy') proto_group.add_argument('--udp', action='store_true', help='UDP proxy') parser.add_argument('-s', '--src', required=True, help='Исходный IP-адрес и порт, например: 127.0.0.1:8000') parser.add_argument('-d', '--dst', required=True, help='IP-адрес и порт назначения, например: 127.0.0.1:8888') output_group = parser. add_mutually_exclusive_group() output_group.add_argument('-q', '--quiet', action='store_true', help='Молчать') output_group.add_argument('-v', '--verbose', action='store_true', help='Говорить громче') аргументы = парсер.parse_args() если args.quiet: LOGGER.setLevel(регистрация.CRITICAL) если args.verbose: LOGGER.setLevel(регистрация.NOTSET) если args.udp: udp_proxy(args.src, args.dst) Элиф args.tcp: tcp_proxy(args.src, args.dst) # конец функции main если __name__ == '__main__': основной()
Однако, когда я запускаю команду testpyProxy.py —udp -d 192.168.2.13:7800 -s 192.168.2.2:7800, я никогда не получаю сообщение:
2009-01-23 19:11:38,786 РАЗМЕР БУФЕРА ОТЛАДКИ : 32768 2009-01-23 19:11:38,786 DEBUG Запуск UDP-прокси... 2009-01-23 19:11:38,786 ОТЛАДКА Источник: 192.168.2.2:7800 2009-01-23 19:11:38,786 ОТЛАДКА Dst: 192.168.2.12:7800 2009-01-23 19:11:38,787 DEBUG Зацикливание прокси-сервера (чтобы остановить, нажмите Ctrl-Break). ..
Этот прокси-сервер Python работает на Centos 7 (192.168.2.2) машина со статистикой подключения порта ethernet из ifconfig:
enp5s0f1: flags=4163mtu 9000 инет 192.168.2.2 сетевая маска 255.255.255.0 широковещательная рассылка 192.168.2.255 inet6 fe80::21b:acff:fe02:af29 prefixlen 64 scopeid 0x20<ссылка> эфир 00:1b:ac:02:af:29 txqueuelen 1000 (Ethernet) Пакеты RX 206136919 байт 494683048962 (460,7 ГиБ) Ошибки RX 0 отброшено 50795 переполнение 0 кадр 0 Пакеты TX 1018446 байт 564508158 (538,3 МБ) Ошибки передачи 0 отброшено 0 превышение пропускной способности 0 несущей 0 коллизий 0
Будем признательны за любую помощь.
ОБНОВЛЕНИЕ:
Я упростил код, который я запускаю, благодаря предложению от tdelaney. На стороне сервера (машина 192.168.2.2) я запускаю следующий код:
#! /USR/бен/python3 импортный сокет BUFFER_SIZE = 2 ** 9 # 1024.