SOKAT и проблемы с чтением из серийного порта

Работаю с неким проприетарным протоколом. Ранее для общения с сервером пользовался tcp/ip сокетом и было все замечательно. Сейчас же клиент находится на той-же машине что и сервер и как следствие общение происходит уже через serial_port. Для того чтобы не переписывать код, использовал вот такую команду:

/usr/bin/socat file:/dev/ttyUSB3,raw,echo=0 tcp-listen:42616,reuseaddr,fork

Команда перенаправляет ввод\вывод в сокет и у меня все заработало. Однако же при тесте выявил проблему, когда я например посылаю команду и ребутаю приложение и подключаюсь снова, то в "сокете" остаются старые сообщения от сервера. Это очень мешает, так как при посылке команды А я должен получать ответ А1, при команде B должен получать ответ B1 и т.д. Протокол чисто бинарный и нет возможности определить на какую команду какой ответ. Вопрос: можно ли настроить socat таким образом, чтобы он при коннекте\дисконекте делал close серийного порта или просто очищал все данные?


Ответы (1 шт):

Автор решения: eri

Просто поменяй местами адреса, ещё добавил бы max-children=1

/usr/bin/socat tcp-listen:42616,reuseaddr,fork,max-children=1 file:/dev/ttyUSB3,raw,echo=0 

Тогда ttyUSB3 порт будет открываться после подключения клиента, закрываться при отключении.

П.С. Но у этого есть небольшая побочка которая случается редко ( и не должна случаться на локалхосте ): если конект не порвался по fyn, то сокат висит как зомби и не отдает порт.

Сейчас использую маленькую программку на python вместо socat:

import asyncio
import serial_asyncio
import sys

class Output(asyncio.Protocol):
    def connection_made(self, transport):
        self.transport = transport
        self.tcp = None
        transport.serial.rts = False 
        
    def data_received(self, data):
        print('>', data)

        self.time = self.loop.time()
        
        if self.tcp:
            self.tcp.write(data)

    def connection_lost(self, exc):
        sys.exit(1)

    def pause_writing(self):
        print(self.transport.get_write_buffer_size())

    def resume_writing(self):
        print(self.transport.get_write_buffer_size())

    def set_tcp(self, transport):
        if self.tcp: 
            self.tcp.close() # отключает старого клиента
        self.tcp = transport
        self.tcp.resume_reading()    

class ProxyServerProtocol(asyncio.Protocol):
    def __init__(self, serial):
        self.serial = serial

    def connection_made(self, transport):
        peername = transport.get_extra_info('peername')
        self.transport = transport
        transport.pause_reading()
        self.serial.set_tcp(transport)

    def data_received(self, data):
        print('<', data)
        self.serial.transport.write(data)


async def main():
    loop = asyncio.get_event_loop()

    serial_transpot, serial_protocol = await serial_asyncio.create_serial_connection(
        loop, 
        Output, 
        sys.argv[1], 
        baudrate=115200
    )

    server = await loop.create_server(
        lambda: ProxyServerProtocol(serial_protocol),
        '0.0.0.0', 5555)

    return server

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.run_forever()
→ Ссылка