LINUX.ORG.RU

непонятки с read() (клиент-сервер)


0

0

есть некий TCP-сервер. В зависимости от полученной команды он возвращает или одну или несколько строк разделенных 0x0A. Хорошо, когда по одной строке: можно использовать Write() и Read() по очереди. А как прочитать несколько строк? Посмотрите на ПСЕВДОКОД while ( (n = read(...)) > 0) print(); он получает первую строку и блокируется в ожидании, а вдруг строк больше не будет? - тогда ощущение что мой клиент висит.

в МАНе сказано: результатом ф-ции Read() будет 0 когда достигнут конец файла, в случае TCP это когда одна сторона закрывает соединение. А у меня нет закрытия соединения, так как же корректно прочитать и одну строку и несколько?


TCP - это поток. Ты хочешь выделить в нем кадры (отделить одни "несколько" строк от других "нескольких"), не зная ни размера ни разделителя. Можно ориентироваться на время (используя, например, select), но это странно и ненадежно.

Тут что-то в протоколе нужно менять. Например, в первой строке передавать количество оставшихся строк.

anonymous
()
Ответ на: комментарий от anonymous

>Например, в первой строке передавать количество оставшихся строк.

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

nil5
()
Ответ на: комментарий от nil5

Поясни строки посылаются сразу вместе и пораздельно

nil5
()

Зачем изобретать велосипед?

Любая передача происходи в дыва приема - сначала заголовк фиксированной длины (заранее известной), потом собственно данные. Длина данных указывается в заголовке, и втормы приемом читается ровно столько сколько указано в заголовке. Моно еще в заголовок вставтить контролную сууму, и еще какие нибуть служебные вещи.... Опираться на рзелители-сепараторы для определения конца передачи ИМНО не стоит (в данном случае)

AIv ★★★★★
()

>в МАНе сказано: результатом ф-ции Read() будет 0 когда достигнут конец файла, в случае TCP это когда одна сторона закрывает соединение.

Плохо Читал маны. о понятии "конец файла" на ближайшее время можешь забыть. а 0 возвращается ещё в тыще случаев кроме закрытия соединения.

А слово select() тебе о чёмто говорит??? если нет то плохо. етот зверь сильно может тя помочь на тему определения конца кадра/пакета

cvv ★★★★★
()
Ответ на: комментарий от idle

например по таймауту или по EINTR в средине таймаута. Стандарт допускает возвращать в етой ситуации 0 вместо -1 и EINTR

cvv ★★★★★
()
Ответ на: комментарий от idle

Хотя вообще ты тоже немало знаеш. Поделись, а? ;-)

cvv ★★★★★
()
Ответ на: комментарий от cvv

я не знаю, о каком стандарте идет речь (в свою очередь,
было бы любопытно узнать).

но почти уверен, что такого быть не может, а если и
есть, то это очень глупый стандарт, imho.

если говорить о linux, то:

если read возвращает что-то != -1, то это - _данные_,
и errno undefined (вообще говоря). будь то сокет, или
обычный файл.

0 - это тоже данные, тот самый конец файла.

idle ★★★★★
()
Ответ на: комментарий от idle

>я не знаю, о каком стандарте идет речь (в свою очередь, было бы любопытно узнать).

POSIX

>если read возвращает что-то != -1, то это - _данные_, и errno undefined (вообще говоря). будь то сокет, или обычный файл.

>0 - это тоже данные

Да так оно и есть. Помоемому вы не поймали мою мысль.

тоесть я не раз ловил ситуацию когда read вернул 0 не на конце связи и не на конце файла. Собственно ету ситуацию я пылся прояснить для человека.

На сколько я помню конец связи надо ловить по EPIPE или чем-то аналогичном(по select()) а не по нулю от read().

cvv ★★★★★
()
Ответ на: комментарий от cvv

> тоесть я не раз ловил ситуацию когда read вернул 0
> не на конце связи и не на конце файла.

этого быть не может. см net/ipv4/tcp.c:tcp_recvmsg()

copied == 0 может быть только если
        sock_flag(sk, SOCK_DONE) // получен fin
или
        sk->sk_shutdown & RCV_SHUTDOWN // был shutdown или fin

> На сколько я помню конец связи надо ловить по EPIPE или чем-то
> аналогичном(по select()) а не по нулю от read().

нет. более того, read может вернуть -1+EPIPE, а после
этого следующий read вернет данные.

idle ★★★★★
()
Ответ на: комментарий от idle

А мы не путаем read() and recv()????. От том как ведёт себя recv() я спорить не могу.

>> На сколько я помню конец связи надо ловить по EPIPE или чем-то

>> аналогичном(по select()) а не по нулю от read().

>нет. более того, read может вернуть -1+EPIPE, а после этого следующий read вернет данные.

А ето уже интересно. первый раз такое слышу. А можно поподробнее???

Я практически всегда обрабатываю ситуации отличные от EINTR && EAGAIN как фатальные и прекращаю дальнейшую работу с дескриптором. Часто даже аварийно завершаю прогу ...

cvv ★★★★★
()
Ответ на: комментарий от cvv

> А мы не путаем read() and recv()????.

sys_read->sock_readv->__sock_recvmsg->sock_common_recvmsg->tcp_recvm
sg

> А ето уже интересно. первый раз такое слышу. А можно поподробнее???

два хоста, 1 и 2.

1: write("something"); // данные "ушли", но 2 их еще не получил.

2: write("bye"); close();

2 получает "something", шлет rst

1 получает "bye" + fin, переходим в TCP_CLOSE_WAIT

1 получает rst, взводится sock->sk_err = EPIPE

1: read() -> -1, errno = sk_err, sk_err очищается

1: read() -> "bye"

1: read() -> 0

idle ★★★★★
()
Ответ на: комментарий от idle

А почему всё настолько развращено????

ето так под линуксом только или под другими юниксами аналогично???

cvv ★★★★★
()
Ответ на: комментарий от cvv

> А почему всё настолько развращено????

потому, что network programming не такая простая вещь :)

> ето так под линуксом только или под другими юниксами аналогично???

не знаю про других, но думаю, что так же.

проблема в том, что многие ошибки/исключения можно
детектировать только асинхронно, иначе пришлось бы
приложению спать в sys_write() пока не придет ACK,
а это, понятно не метод.

read() возвращает ошибку, и это естественный подход,
как еще дать приложению знать, что ранее отправленные
данные не были доставлены?

btw, write() тоже вернул бы ошибку, но ведь ядро не
знает, будет ли приложение что-то еще делать с этим
soсket.

так что все очень логично, учитывая, что tcp - это
reliable протокол. при правильном программировании,
конечно :)

idle ★★★★★
()
Ответ на: комментарий от cvv

> > > Стандарт допускает возвращать в етой ситуации 0 вместо -1 и EINTR
> > я не знаю, о каком стандарте идет речь (в свою очередь, было бы любопытно узнать).
> POSIX

где ???? нет, серьезно, вы ничего не напутали?

где можно это прочитать? не верю.

idle ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.