2

I'm trying to write a program that connects to a server opened with nc -v -l 1337 on another terminal, and redirects stdin, stdout, stderr to the socket. Meaning, the other terminal will write to the socket, and my program will read it with getchar() and respond using printf().

I came across something strange - everything works fine if I comment out the first use of printf (before dup2(sockfd,1)). If not, printing does nothing. What can cause this?

int main() 
{ 
    int sockfd, connfd; 
    struct sockaddr_in servaddr, cli; 

    // socket create and varification 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    bzero(&servaddr, sizeof(servaddr)); 

    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    servaddr.sin_port = htons(1337); 

    connect(sockfd, (SA*)&servaddr, sizeof(servaddr));
    dup2(sockfd,0);
//---------------------------
//  printf("%s\n","hi" );
//---------------------------
    dup2(sockfd,1);
    dup2(sockfd,2);

    char buff[80]; 
    int n; 
    while(1){
        n = 0;
        while ((buff[n++] = getchar()) != '\n');
        buff[n-1] = 0;
        printf("message %s excepted\n",buff ); 
    }
    // close the socket 
    close(sockfd); 
} 
Nadav G
  • 23
  • 4

3 Answers3

0

Fix:

You need to tell your program to flush stdout when writing to it:

    while(1){
        n = 0;
        while ((buff[n++] = getchar()) != '\n');
        buff[n-1] = 0;
        printf("message %s excepted\n",buff ); 

        /* ask the system to flush stdout */
        fflush(stdout);
    }

Reason: (I'm just guessing)

Not all FILE stream are buffered the same.

FILE stream connected to a terminal will be flushed when a \n is to be print.

FILE stream connected to a socket will be flushed when buffer is full.

By calling printf("...\n"); before dup2();, you force the first behavior.

Mathieu
  • 6,922
  • 6
  • 27
  • 37
  • This explanation sounds very reasonable (Though it would be nice if I could find it documented somewhere :-), thanks, That's the answer I was looking for! – Nadav G Apr 08 '19 at 11:46
0

Your program is doing what is expected, dup2(sockfd,0); will close the standard input of your client program (that is, the text entered from your keyboard in the terminal where you launched your program), and use sockfd as your new standard input. Quoted from here:

dup2() makes newfd be the copy of oldfd, closing newfd first if necessary

To put this in evidence, try to launch your listening socket program this way :

  • cat | nc -v -l 1337 in terminal 1
  • wrap your socket client program with strace (e.g. strace a.out) in terminal 2

The text typed in terminal 1 (where you launched the server listening on port 1337) will be sent over the socket, received in terminal 2 over fd 0 (which is now a copy of sockfd), and sent back over the socket because of the redirection of standard output (fd 1) to sockfd.

You may want to comment out dup2(sockfd,1); if you'd rather not send the text back to the server but have it displayed to terminal 2 instead. Alternatively, you may want to comment out dup2(sockfd,0); to keep the standard input of your client program to your keyboard and send the text entered from terminal 2 over the socket.

Not sure that answers your question, but I think strace + cat will help you understand how you can manage the various files descriptors in place.

Hope this helps!

Philippe Sultan
  • 1,601
  • 12
  • 21
0

I would say this could be a buffering issue. A common fix, as suggested is flushing the socket, otherwise try setting the buffer for stdout to 0 might fix this behaviour.

setbuf(stdout, NULL);