Redirecting stdout/stdin to socket

Redirecting stdout/stdin to socket

Post by Jenny Fors » Thu, 24 Jul 1997 04:00:00



This is a multi-part message in MIME format.

--------------55F9562B3659
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

I'm writing a small server program in C. The program listens on a
socket, accepts a connection from a client, and then forks and does
execlp() to start up a program.

What I want is for stdin/stdout from this program to go through the
socket to the client, so that everything the user types in the client
window is sent straight to the program's stdin. I tried using dup2(),
and it works fine for the output from the program (which shows up in the
client's window just as intended), but it doesn't seem to get any of the
input that I send from the client.

I looked through the network programming faq and found something about
the problem being related to the buffering of input/output (it said that
the buffers can only be explicitly flushed using write() or read() ) and
the solution was to use something called a pty, instead of a socket. If
this is the answer to my problem, could anybody please explain this
further, and give me some help on how to use it? And by the way, if this
is the reason my approach doesn't work, how come all the output comes
through fine?

The code for my server is attached...

Thank you!
                Jenny Forss

--------------55F9562B3659
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="genserver.c"

/***************************************************************************
 *
 *      Filename: genserver.c
 *      Project :

 *      Purpose :
 *
 ***************************************************************************/

/******************************** includes ****************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

/*** defines ***/

#define READ     0
#define WRITE    1
#define debug    1

#define GENESIS "/cit/genesis2/genesis"
#define GENESIS_FLAGS "Neurokit"

/**************************************/
/* MAIN                               */
/**************************************/
void
main(int argc, char **argv)
{
  int n, status;
  int pid;
  int sockfd, client_sockfd, res, len;
  struct sockaddr_in serv_addr;
  struct sockaddr client_addr;
  fd_set readfds; /* for select */

  /******************************************/
  /* SETTING UP...                          */
  /******************************************/

  /* Create socket for incoming connections */
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) <= 0) {
    perror("Couldn't create socket.");
    exit(2);
  }

  /* Fill in structure for socket */
  serv_addr.sin_port = htons(9191);

  /* Bind the socket to the address in the structure */
  res = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
  if (res < 0) {
    printf("Failed to bind socket to port 9191.\n");
    exit(2);
  }

  /*******************************************/
  /* START LISTENING FOR CONNECTIONS...      */
  /*******************************************/

  printf("Listening for connections from clients...\n");
  res = listen(sockfd, 5);
  if (res < 0) {
    perror("Couldn't listen on port 9191.\n");
    exit(1);
  }

  /*******************************************************/
  /* ETERNAL LOOP TO ACCEPT CONNECTIONS &                */
  /* SPAWN OFF GENESIS PROCESSES                         */
  /*******************************************************/
  while (1) {
    /* prepare for select */
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);

    if (select(sockfd + 1, &readfds, NULL, NULL, NULL) < 1) {
      perror("no client connection");
      exit(1);
    }

    /* now accept the connection */
    len = sizeof(client_addr);
    if ((client_sockfd = accept(sockfd, &client_addr, &len)) < 0) {
      perror("Couldn't accept connection from client.");
      exit(1);
    }

    printf("Connection accepted.\n");

    /*
     * Fork off a Genesis process.
     */
    switch( pid = fork() )
      {
      case 0 :                  

        /* Redirect stdout+stdin to the socket */
        assert( dup2( client_sockfd, WRITE) == WRITE);
        assert( dup2( client_sockfd, READ)  == READ);

        /*
         * Time to execute a Genesis process (flags defined at the top of
         * this file...)
         */
        execlp(GENESIS,
               GENESIS,
               GENESIS_FLAGS,
               (char *)0);
        fprintf(stderr," %s: Starting Genesis: cannot execlp!",argv[0]);
        exit(1);

      case -1:                  /* Fail! */
        fprintf(stderr," %s: unable to fork Genesis process",argv[0]);
        exit(1);

      } /* end of fork */
  } /* end of main */    

Quote:}

--------------55F9562B3659--
 
 
 

Redirecting stdout/stdin to socket

Post by Jenny Fors » Thu, 24 Jul 1997 04:00:00


Hi Andrew,

Thanks for replying to my message!

Quote:>  - is the invoked application interactive? Is it attempting to do
>     character-by-character input?

Yes, in fact it is... :-/ The application normally displays its
own command prompt to the user, and that's how you interact
with it, so I guess it would expect to talk to a tty device.

Quote:>  - what is the client program?

The client program was written by me (in Java). It's very
simple - just an interface for displaying output and sending
input to the server (i.e. the invoked application). I also
tried doing telnet to the server port, and the same thing
happened.

I really appreciate your help!
Regards,
                Jenny Forss

 
 
 

Redirecting stdout/stdin to socket

Post by Andrew Giert » Fri, 25 Jul 1997 04:00:00


 Jenny> What I want is for stdin/stdout from this program to go
 Jenny> through the socket to the client, so that everything the user
 Jenny> types in the client window is sent straight to the program's
 Jenny> stdin. I tried using dup2(), and it works fine for the output
 Jenny> from the program (which shows up in the client's window just
 Jenny> as intended), but it doesn't seem to get any of the input that
 Jenny> I send from the client.

What is the client? Are you using telnet, or have you written some
program of your own for that?

 Jenny> I looked through the network programming faq and found
 Jenny> something about the problem being related to the buffering of
 Jenny> input/output (it said that the buffers can only be explicitly
 Jenny> flushed using write() or read() ) and the solution was to use
 Jenny> something called a pty, instead of a socket. If this is the
 Jenny> answer to my problem, could anybody please explain this
 Jenny> further, and give me some help on how to use it? And by the
 Jenny> way, if this is the reason my approach doesn't work, how come
 Jenny> all the output comes through fine?

The usual problem with this approach occurs when the invoked
application is interactive, and therefore assumes that it is talking
to a tty device (or something with the characteristics of a tty
device). Sockets, on the other hand, look more like pipes to the
program.

What's happening to your input I can only guess at, since your setup
of the file descriptors seems to be adequate (though you're leaving
excess FDs open when invoking the application, not good).

So, some questions:

  - is the invoked application interactive? Is it attempting to do
    character-by-character input?

  - what is the client program?

--
Andrew.

comp.unix.programmer FAQ: see <URL: http://www.erlenstar.demon.co.uk/unix/>
                           or <URL: http://www.whitefang.com/unix/>

 
 
 

Redirecting stdout/stdin to socket

Post by Jeff Hedgpet » Fri, 25 Jul 1997 04:00:00



> What I want is for stdin/stdout from this program to go through the
> socket to the client, so that everything the user types in the client
> window is sent straight to the program's stdin. I tried using dup2(),
> and it works fine for the output from the program (which shows up in the
> client's window just as intended), but it doesn't seem to get any of the
> input that I send from the client.

> I looked through the network programming faq and found something about
> the problem being related to the buffering of input/output (it said that
> the buffers can only be explicitly flushed using write() or read() ) and
> the solution was to use something called a pty, instead of a socket. If
> this is the answer to my problem, could anybody please explain this
> further, and give me some help on how to use it? And by the way, if this
> is the reason my approach doesn't work, how come all the output comes
> through fine?

 I am an amatuer at socket programming, but you might try setting
TCP_NODELAY to disable the Nagle buffering.  You mentioned it above,
but I don't think that even write() and read() actually flush the
buffer.  I would guess that the server is sending enough data at a
time to be immediately sent, while the client is only writing a byte
at a time and being buffered.

 I could be completely wrong, so you can check out the FAQ that I have:
http://kipper.york.ac.uk/~vic/sock-faq

Hope this helps,
Jeff

_________________________________________________________
Jeff Hedgpeth   System Administration
Edward Jones    jeff dot hedgpeth at edwardjones dot com
                        St. Louis, MO, USA
I do not speak for Edward Jones.

 
 
 

Redirecting stdout/stdin to socket

Post by Jeff Hedgpet » Fri, 25 Jul 1997 04:00:00



>  I could be completely wrong, so you can check out the FAQ that I have:
> http://kipper.york.ac.uk/~vic/sock-faq

I just noticed that a previous reply was by someone (Andrew Gierth) who
played a big part in creating the faq I just mentioned.  Just in case
I contradicted him, you can more easily decide who to listen to. :)

_________________________________________________________
Jeff Hedgpeth   System Administration
Edward Jones    jeff dot hedgpeth at edwardjones dot com
                        St. Louis, MO, USA
I do not speak for Edward Jones.