Is this case is normal when programming in socket?

My program has two threads, one is for sender and another one is receiver,

  1. The receiver loop forever and accept and receive data from sender.
  2. The sender may send message if necessary and terminated when the job finished (I create a new thread when new service is needed).

Now I have 2 questions, the first one is that when I use Ctrl+C to terminate my program, and use netstat -an command to see the network connection, I saw some connections are still here and their status are ESTABLISHED, is it normal?

This is a bit confusing, as you are describing one end of a full duplex situation, or is it both ends of a half duplex situation? A TCP socket is full duplex, but many of the protocol writers decided to run half-duplex. Now, you are the protocol writer.

Even if the client or server goes down, the socket may remain open in some state for a while, in case a late resend for end of file is received. Also, if anyone inherited the fd of the socket, it is not closed.

Hi, I am using TCP socket now, I don't understand what is 'a late resend for end of file is received'? Would you please describe it in detail?

TCP is achieved with packets, the first is flagged syn, then syn-ack, the middle are probably ack, until fin and fin-ack are exchanged. The client sends syn to connect, and the server send syn-ack. The fd close sends fin and the other end sends fin-ack. If a packet is lost, the sending end might retry minutes later. So, like linger, there is a socket residue to answer any belated questions.

When you said accept, did you mean it is a server? Here is a generic server:

$ cat mysrc/u_inetd.c 
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#define P_EEXIT fprintf(stderr,"Abnormal exit at %s:%d\n",__FILE__,__LINE__),exit(1)
int main( int argc, char **argv ){
        int i, s, ns, loa, t_on = 1, ka = 10, only1 = 0, maxbuf=65535 ;
        union {
                struct sockaddr sa ;
                struct sockaddr_in sin ;
        } u ;
        struct sigaction siga ;
        u.sin.sin_port = 0 ;
        u.sin.sin_addr.s_addr = INADDR_ANY ;
        for ( i = 1 ; i < argc ; i++ ){
                if ( !strcmp( argv, "-l" )){
                        u.sin.sin_addr.s_addr = INADDR_LOOPBACK ;
                } else if ( !strcmp( argv, "-o" )){
                        only1 = 1 ;
                } else if ( u.sin.sin_port == 0 ){
                        if ( 1 > atoi( argv )){
                                break ;
                        }
                        u.sin.sin_port = atoi( argv );
                }
                else    /* must be command */
                        break ;
        }
        if ( u.sin.sin_port == 0
          || i == argc ){
                printf(
"Usage:  %s [ -l ] [ -o ] <port> <cmd> [<cmd args>]\n"
"\n"
"Listens on port for tcp connections, and for every connection,\n"
" runs <cmd> with any <cmd args>\n"
"  and with the socket as stdin and stdout (but stderr is preserved)\n"
"   under the user's id.  (Be careful!)\n"
"\n"
"The -l option restricts connections to clients on the same host\n"
" for greater security.\n"
"The -o option restricts the server to only one (1) service at a time\n"
" for commands that need exclusive control of a resource,\n"
" by waiting for child termination.  This can result in a hung server.\n"
"The <cmd> must be exec() compatible, so if it is not a sh shell script,\n"
" make sure to have '#!<full_path_of_interpreter> [ <one_arg> ]' as line 1.\n"
"\n",
                        argv[0] );
                exit( 1 );
        }
        /* ensure that no fd's are open that are not needed,
                as sh does not allow >&##       */
        for ( s = 0 ; s < 128 ; s++ ){
                if ( s != 2 )
                        close( s );
        }
        if ( 0 > ( s = socket( PF_INET, SOCK_STREAM, NULL ))){
                perror( "socket( PF_INET, SOCK_STREAM, NULL )" );
                P_EEXIT ;
        }
        u.sin.sin_family = AF_INET ;
        if ( setsockopt(  s, IPPROTO_TCP, TCP_NODELAY, (char *)&t_on, sizeof(int))){
                 perror( "setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&t_on, sizeof(int))" );
                P_EEXIT ;
        }
        if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&t_on,
                sizeof(int))){
                perror( "setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&t_on, sizeof(int) )" );
                P_EEXIT ;
        }
        if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char*)&ka,
                sizeof(int))){
                perror( "setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char*)&ka, sizeof(int) )" );
                P_EEXIT ;
        }
        if ( setsockopt(  s, SOL_SOCKET, SO_RCVBUF, (char *)&maxbuf, sizeof(int))){
                 perror( "setsockopt( s, IPPROTO_TCP, SO_RCVBUF, (char *)&maxbuf, sizeof(int))" );
                P_EEXIT ;
        }
        if ( setsockopt(  s, SOL_SOCKET, SO_SNDBUF, (char *)&maxbuf, sizeof(int))){
                 perror( "setsockopt( s, IPPROTO_TCP, SO_SNDBUF, (char *)&maxbuf, sizeof(int))" );
                P_EEXIT ;
        }
        if ( bind( s, &u.sa, sizeof(u.sa))){
                perror( "bind()" );
                P_EEXIT ;
        }
        if ( listen( s, 256 )){
                perror( "listen( s, 256 )" );
                P_EEXIT ;
        }
        siga.sa_handler = NULL ;
        sigemptyset( &siga.sa_mask );
        siga.sa_flags = SA_NOCLDWAIT ;
        sigaction( SIGCHLD, &siga, NULL );
next:
        loa = sizeof(u.sa);
        if ( 0 > ( ns = accept( s, &u.sa, &loa ))){
                if ( errno == EINTR
                  || errno == EAGAIN ){
                        goto next ;
                }
                perror( "accept( s, &u.sa, sizeof(u.sa) )" );
                P_EEXIT ;
        }
refork:
        switch ( fork()){
        case -1 :
                sleep( 1 );
                goto refork ;
        case 0 :
                break ;
        default:                /* Parent */
                close( ns );
                if ( only1 ){
                        do {
                                wait( NULL );
                        } while ( errno != ECHILD );
                }
                goto next ;
        }
        /* child */
        close(s);
        do {
                s = dup(ns);
        } while ( s < 1 && s >= 0 );
        if ( ns > 2 ){
                close(ns);
        }
        execvp( argv, argv + i );
        /* should never get here */
        perror( "execvp( argv, argv + i )" );
        P_EEXIT ;
}

Which program is terminated? The client or the server?

Assuming the default handling for Ctrl+C (terminate process), your description seems strange. When the process is terminated, the kernel closes the opened sockets, causing a FIN segment to be sent out. Following the TCP state transition diagram, when a FIN segment is received in ESTABLISHED, the state should go either to CLOSE_WAIT or FIN_WAIT_1.

Of course, if many clients are connected and one is killed, the other established connections would remain.

Well, did you write a client or a server or both, and which did you have interactive when you and ^C and the shell killed it?

If you have root, lsof tells you more about sockets.

Using my u_inetd server and a high port, anyone can create a server, even with a shell script. I have not written a listener for a while, since this takes care of my every need.

If you write a client, and it connects, and you kill it, the connection established immediately transitions to another state on most systems.

$ psm 9090
UID       PID PPID C STIME  TTY TIME COMMAND
dgp     16824    1 0 Jun 14 ?   0:04 u_inetd 9090 http2env
 /home/dgp/myweb
$ (
netstat -an >/tmp/a
( echo hello ; sleep 2 )|telnet localhost 9090 &
sleep 1
netstat -an >/tmp/b
sleep 2
kill -9 $!
netstat -an >/tmp/c
diff /tmp/a /tmp/b |grep 9090
echo ====
diff /tmp/b /tmp/c |grep 9090
)
[1]     12205
Trying...
Connected to localhost.
Escape character is '^]'.
> tcp        0      0  127.0.0.1.9090         127.0.0.1.59702         ESTABLISHED
> tcp        0      0  127.0.0.1.59702        127.0.0.1.9090          ESTABLISHED
====
> tcp        0      0  127.0.0.1.59702        127.0.0.1.9090          TIME_WAIT
< tcp        0      0  127.0.0.1.9090         127.0.0.1.59702         ESTABLISHED
< tcp        0      0  127.0.0.1.59702        127.0.0.1.9090          ESTABLISHED
$

Hi DGPickett,

Though your code is great for teaching purposes, does it offer any advantage over netcat (aka. nc) ?

Cheers,
Lo�c

I have not studied netcat. Maybe it can do all this, too. Sometimes less is more. My u_inetd is the server side only, tcp only. It is a user's, one-app at a time, inetd daemon. Just as telnet is a universal client for tcp, this is a universal server. I figured it might help the original questioner sort out how to listen. Even if you know how to listen and know how to connect, you still need protocol so both ends do not hang both listening or sending only in a half duplex scenario.