Запрет записи в сокет до того, как другая сторона примет запрос - PullRequest
1 голос
/ 15 июня 2010

Я реализую FTP-подобный протокол в Linux (домашнее задание) и столкнулся со следующей проблемой: клиент может подключиться () и написать () до того, как другой стороне удастся выполнить accept () (но послеэто действительно слушало ()).Как я могу предотвратить работу операции записи, не полагаясь на передачу сообщений типа «Принять успешно, вы можете написать сейчас» в другом канале связи?

Ответы [ 2 ]

4 голосов
/ 15 июня 2010

Вызов connect () не будет возвращен, пока не будет установлено TCP-соединение. Данные не достигнут серверного приложения, пока не будут приняты вызовы на стороне сервера (). Однако после установления TCP-соединения клиент может начать отправку данных. Он будет буферизован стеком сервера, пока не будет прочитан приложением сервера.

Какова цель предотвращения операции записи? Механизм окна TCP приостанавливает поток данных, если сервер задерживается при вызове accept ().

1 голос
/ 15 июня 2010

Посмотрите на трехстороннее рукопожатие TCP с точки зрения времени:

  1. SYN от клиента к серверу
    • отправлено клиентом на T1
    • получено сервером на T2
  2. SYN-ACK от сервера к клиенту
    • отправлено сервером на T3
    • получено клиентом на T4
  3. ACK от клиента к серверу
    • отправлено клиентом на T5
    • получено сервером на T6

Блокировка connect(2) на клиенте возвращается на T5, тогда как блокировка accept(2) возвращается на T6, а T5 строго меньше T6. Так что да, это временное окно, в котором клиент может начать отправку данных, думая, что соединение установлено. Если клиент потерял ACK, сервер застрял в accept(2). Это похоже на известную гонку с блокирующей комбинацией select(2) / accept(2).

Вы не можете предотвратить отправку клиентом до того, как accept(2) вернется на сервер без отправки сервером чего-либо.

Обходной путь - сделать сокет сервера неблокирующим и полагаться на select(2) / poll(2) / epoll(4).

...