I'm implementing an FTP like protocol in Linux (homework) and I came upon the following problem: the client may be able to connect() and write() before the other side managed to do accept() (but after it did listen()). How can I prevent the write operation from working without relying on passing messages like "accept succeeded, you can write now" in a different communication channel?
views:
39answers:
2The connect() call will not return until a TCP connection is established. Data won't reach the server app until the server side calls accept(). However, once the TCP connection is established the client may start sending data. It will be buffered by the server stack until it is read by the server app.
What is the purpose for preventing the write operation? The TCP window mechanism will pause data flow if the server is delayed in calling accept().
Look at the TCP three-way handshake in terms of times:
SYN
from client to server- sent by client at
T1
- received by server at
T2
- sent by client at
SYN-ACK
from server to client- sent by server at
T3
- received by client at
T4
- sent by server at
ACK
from client to server- sent by client at
T5
- received by server at
T6
- sent by client at
Blocking connect(2)
on the client returns at T5
, while blocking accept(2)
returns at T6
, and T5
is strictly less then T6
. So yes, that's the time window where client can start sending data thinking the connection is established. If client's ACK
is lost the server is stuck in accept(2)
. This is similar to well-known race with blocking select(2)
/accept(2)
combination.
You can't really prevent the client from sending before accept(2)
returns on the server without server sending something.
A way around this is making the server socket non-blocking and relying on select(2)
/poll(2)
/epoll(4)
.