So, let me correct my diagram.
As I mentioned, with TCP, there is a server who listens on a specific
port/IP. The client issues a connect. When the server accepts the
connection, a new port is established. The client, only sends on the known
port, but it is waiting on a port assigned by the OS.
Here is the sequence:
Server Client
Listen on port 23 Connect on port 23 (wait port 7899).
Accept connection Connect returns 0 (success)
Server may reissue listen.
At this point, the Server is still receiving on port 23 and sending on port
7899. The client is sending on port 23 and receiving on port 7899. The
reason the server can both listen and receive on the same port is that when
the connection is accepted by the kernel, the kernel adds it to the TCP
table as an established connection assocated with a client ip/port.
Many times, a new process (or thread) is created at the server:
// Server is in a tight loop listening on some port. In this case, the
accept is embedded in the child, but it can also be in the parent before
the fork(). The thread paradigm also works.
while(1) {
rv = listen(s, 10);
if (rv == -1) {
// handle error
} else {
child = fork();
if (child == -1) {
// handle error
} else if (child != 0) { // parent
continue; // Continue loop
} else { // child process
news = accept(s, (struct sockaddr *)(&newaddr), &newaddr_len);
close(s);
// process receives and sends
close(news);
return 0; // exit child process
}
}
}
// parent
--
Jerry Feldman