Advertisement

a tough question to phrase

Started by May 15, 2005 02:57 PM
7 comments, last by locke1105 19 years, 9 months ago
I want to be able to send/recv packets of information between my game and my server, while performing other actions (ex. typing a message). I just cant understand how to do it. In my current program, i can recv packets or type. And untill I'm done typing, no packets can get through. I want the option to type a message to be avalible all the time, and I cant afford to not recv packets because I am typing. The program is using TCP, I cant think of anyway that could help, but I felt like typing it. I know it is possible to do, because I've seen it done, but I don't get the philosophy behind it. Thanks in advance for all replies... Happy coders. [grin]
What you are refering to is non-blocking input/output.

Say you have something like this:
forever read character from input send character to socket do other stuff

When you read a character you normally 'get stuck' in the call until data is available, until a user hits a key on the keyboard in this case.

What you want is some this kind of logic:
forever  if character from input avalable?     read input     send character to socket  do other stuff     

This way you can do your other stuff without waiting for the user to type a character.

The concept of non-blocking IO can also be applied to sockets and all other types of IO interaces.

On UNIX you can use select() to check if any data is avalable on sockets, stdio and files. I don't know how this is for Windows though.
Advertisement
If you want to type, asynchronously, on UNIX, you need to set the TTY driver in un-buffered mode, and use non-blocking reads (or select()) to check for input. This is hugely more complicated that it "ought" to be, because of the 1970 teletype heritage of UNIX.

This is the source to a simple serial port communication program I wrote a while back. You may want to steal the functions setupser() and friends.

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/fcntl.h>#include <termios.h>#define BAUD B19200struct portinfo_t {  int fd_in;  int fd_out;  struct termios in_orig;  struct termios in_nu;  struct termios out_orig;  struct termios out_nu;};intopenser( char const * port, portinfo_t * info ){  info->fd_out = -1;  info->fd_in = open( port, O_RDWR );  if( info->fd_in < 0 ) return -1;  info->fd_out = info->fd_in;  return 0;}intopenstd( portinfo_t * info ){  info->fd_in = 0;  info->fd_out = 1;  return 0;}voidsetupser( portinfo_t * info ){  tcgetattr( info->fd_in, &info->in_orig );  info->in_nu = info->in_orig;  cfmakeraw( &info->in_nu );  cfsetispeed( &info->in_nu, BAUD );  cfsetospeed( &info->in_nu, BAUD );  //fixme: turn off flow control  info->in_nu.c_cflag &= ~(CRTSCTS);  tcsetattr( info->fd_in, TCSAFLUSH, &info->in_nu );  info->out_orig = info->in_orig;  info->out_nu = info->in_nu;  if( info->fd_out != info->fd_in ) {    tcgetattr( info->fd_out, &info->out_orig );    info->out_nu = info->out_orig;    cfmakeraw( &info->out_nu );    cfsetispeed( &info->out_nu, BAUD );    cfsetospeed( &info->out_nu, BAUD );    tcsetattr( info->fd_out, TCSAFLUSH, &info->out_nu );  }}voidsetupstd( portinfo_t * info ){  tcgetattr( info->fd_in, &info->in_orig );  info->in_nu = info->in_orig;  cfmakeraw( &info->in_nu );  tcsetattr( info->fd_in, TCSAFLUSH, &info->in_nu );  info->out_orig = info->in_orig;  info->out_nu = info->in_nu;  tcsetattr( info->fd_out, TCSAFLUSH, &info->out_nu );}voidteardownser( portinfo_t * info ){  tcsetattr( info->fd_in, TCSAFLUSH, &info->in_orig );  tcsetattr( info->fd_out, TCSAFLUSH, &info->out_orig );}voidteardownstd( portinfo_t * info ){  tcsetattr( info->fd_in, TCSAFLUSH, &info->in_orig );  tcsetattr( info->fd_out, TCSAFLUSH, &info->out_orig );}voidclosestd( portinfo_t * info ){}voidcloseser( portinfo_t * info ){  close( info->fd_in );  if( info->fd_out != info->fd_in ) {    close( info->fd_out );  }  info->fd_in = info->fd_out = -1;}intmain( int argc, char * argv[] ){  if( argc != 2 ) {    fprintf( stderr, "usage: ser #\n" );    exit( 1 );  }  int s = atoi( argv[1] );  if( s < 0 || s > 3 ) {    fprintf( stderr, "error: port %d is not allowed\n", s );    exit( 2 );  }  char name[ 40 ];  sprintf( name, "/dev/ttyS%d", s );  portinfo_t portinfo_ser;  portinfo_t portinfo_std;  fprintf( stderr, "opening %s\n", name );  if( openser( name, &portinfo_ser ) == -1 ) {    fprintf( stderr, "error: cannot open %s\n", name );    exit( 3 );  }  fprintf( stderr, "opening tty\n" );  if( openstd( &portinfo_std ) == -1 ) {    fprintf( stderr, "error: cannot take over stdin/stdout\n" );    exit( 4 );  }  fprintf( stderr, "setting up\n" );  setupser( &portinfo_ser );  setupstd( &portinfo_std );  int n = portinfo_ser.fd_in;  if( portinfo_ser.fd_out > n ) n = portinfo_ser.fd_out;  if( portinfo_std.fd_in > n ) n = portinfo_std.fd_in;  if( portinfo_std.fd_out > n ) n = portinfo_std.fd_out;  ++n;  bool isquote = false;  fprintf( stderr, "ready\n" );  while( 1 ) {    fd_set in;    FD_ZERO( &in );    FD_SET( portinfo_ser.fd_in, &in );    FD_SET( portinfo_std.fd_in, &in );    fprintf( stderr, "calling select\n" );    if( select( n, &in, 0, 0, 0 ) > 0 ) {      char c;      if( FD_ISSET( portinfo_ser.fd_in, &in ) ) {        fprintf( stderr, "reading from in\n" );        read( portinfo_ser.fd_in, &c, 1 );        fprintf( stderr, "got %d from in: " );        // always echo immediately        write( portinfo_std.fd_out, &c, 1 );        fprintf( stderr, "\n" );      }      if( FD_ISSET( portinfo_std.fd_in, &in ) ) {        fprintf( stderr, "reading keyboard\n" );        read( portinfo_std.fd_in, &c, 1 );        if( isquote ) {          if( c == 'q' ) {            break;          }          else {            char str[ 2 ];            str[ 0 ] = '~';            str[ 1 ] = c;            fprintf( stderr, "writing modem: ~ %d\n", c );            write( portinfo_ser.fd_out, str, 2 );            isquote = false;          }        }        else if( c == '~' ) {          isquote = true;        }        else {          fprintf( stderr, "writing modem: %d\n", c );          write( portinfo_ser.fd_out, &c, 1 );        }      }    }    else {      break;    }  }  teardownser( &portinfo_ser );  teardownstd( &portinfo_std );  closestd( &portinfo_std );  closeser( &portinfo_ser );  return 0;}

enum Bool { True, False, FileNotFound };
Look up the Select() function
-www.freewebs.com/tm1rbrt -> check out my gameboy emulator ( worklog updated regularly )
I think I'm on the right track, over the last few days I've been testing a few possible solutions. I need to know if there is any function that anyone knows of that doesn't "prompt" or wait for someone to push enter. I was thinking that each loop it would allow you to type one character into the buffer and it would take that character and add it to the end of the string. But the only commands I know(that certainly don't get the job done) are cin, scanf(), kbhit(). Im sure that there is a command that takes input but doesn't wait for it, but I can't find it in stdio.h or conio.h. Thanks.
If you want to keep the server and console seperate, why not put the server on a seperate thread?
Advertisement
I don't know what you are talking about. My question is about how to recv packets while being able to accept player input. Actually to be more specific, I just currently want to know how to get input but not pause the loop for it.
Quote:
I need to know if there is any function that anyone knows of that doesn't "prompt" or wait for someone to push enter.


What's wrong with the code I posted? It does exactly that.
enum Bool { True, False, FileNotFound };
I'm very sorry hplus, I forgot to post that I couldn't get your code to work. It was rather inconiderate of me to not inform you. I do not have unix (shame on me) and I tried to convert it to win32 to no avail. I think I am on the right track, I got a tutorial on so called "asynchronous" i/o, that I have yet to read, I hope it will lead me closer to my goal. Thanks all.

This topic is closed to new replies.

Advertisement