Home Papers Reports Projects Code Fragments Dissertations Presentations Posters Proposals Lectures given Course notes
<< 1. TCP IP Sockets in C3. TCP IP Sockets in Java >>

2. UDP IP Sockets in C

Werner Van Belle1 - werner@yellowcouch.org, werner.van.belle@gmail.com

1- Programming Technology Lab (PROG) Department of Computer Science (DINF) Vrije Universiteit Brussel (VUB); Pleinlaan 2; 1050 Brussel; Belgium

Abstract :  These are course notes I made to teach distributed systems for the VUB. I used them in 1998 to 1999, 1999 to 2000

Reference:  Werner Van Belle; UDP IP Sockets in C;
See also:
Tcp/Ip sockets


Info

Datagramcommunicatie is net zoals streamcommunicatie gebaseerd op het gebruik van socketparen. Communicatie daarentegen wordt tot stand gebracht door een bericht te sturen naar de lokale socket en er een bestemmingsadres aan mee te geven. Het ontvangen van berichten gebeurt op de lokale socket die, op het ogenblik een packet binnenkomt, vermeld van waar het gekomen is. In tegenstelling tot stream communicatie is deze vorm van communicatie eerder peer to peer omdat er geen duidelijke luisteraar en zender is. Ter verduidelijking:

Beide communicerende processen gebruiken een socket call om een socket te creeren. Het eerste argument bevat het communicatiedomein (normaal internet, genoteerd AF_INET). Het tweede argument bevat welk soort connectie gewenst is. (Dit is SOCK_DGRAM). De laatste parameter bepaalt welk onderliggend netwerkprotocol effectief gehanteerd wordt. Voor datagrams wordt vaak als protocol PROTO_UDPIP gebruikt. Als deze waarde op 0 staat wordt zelf een geschikt protocol gekozen. De socket call retourneert een waarde die gebruikt kan worden als filedescriptor om data van te lezen en naartoe te sturen.

Beide processen moeten nu hun socket (die enkel in geheugen bestaat) verbinden aan een lokaal adres. De system call bind wordt hiervoor gebruikt. Meestal verbind de client zijn socket adres aan de eerste vrije lokale poort en zal de server zijn socket verbinden aan een op voorhand 'afgesproken' lokale poort.

Het zendende proces gebruikt een sendto call met argumenten die specifieren door welke socket data verstuurd moet worden en naar welk adres het bericht verstuurd moet worden. De sendto call retourneert hoeveel karakters doorgezonden werden. Aangezien we met datagramcommunicatie werken is er geen acknowledge aanwezig en hebben we geen zekerheid over het toekomen van berichten. Desalnietemin wordt wel een error weergegeven als het packet te groot was om verstuurd te worden.

#include <sys/types.h>
#include <sys/socket.h>
#include <err.h>
#include <errno.h>
#include <linux/in.h>
#include <netdb.h>

/* UDP */
void main(void)
{
   int s; char b;
   int aantal;
   struct hostent *h;
   struct sockaddr_in localaddress;
   struct sockaddr_in serveraddress;
   /* socket adres maken */
   s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
   if (s==-1) printf("socket: %s\n",strerror(errno));
   /* socket binden aan een deftig adres */
   memset(&localaddress,0,sizeof(struct sockaddr_in));
   localaddress.sin_port=htons(0);
   localaddress.sin_family=AF_INET;
   h=gethostbyname("4.4.9.1");
   memcpy(&localaddress.sin_addr,h->h_addr,h->h_length);
   if (-1==bind(s,(struct sockaddr_in*)&localaddress,sizeof(struct sockaddr_in)))
     printf("bind: %s\n",strerror(errno));
   /* schrijven van data */
   memset(&serveraddress,0,sizeof(struct sockaddr_in));
   serveraddress.sin_port=htons(0);
   serveraddress.sin_family=AF_INET;
   h=gethostbyname("4.4.9.1");
   memcpy(&serveraddress.sin_addr,h->h_addr,h->h_length);
   aantal=sendto(s,"howdy",6,0,(struct sockaddr_in*)&serveraddress,sizeof(struct sockaddr_in));
   printf("%d send\n",aantal);
}

Het ontvangende proces gebruikt de recvfrom call met als argumenten de ontvangende socket (lokaal dus) een pointer naar een buffer en een referentie naar een structuur die de zender zal bevatten na de ontvangst.

#include <sys/types.h>
#include <sys/socket.h>
#include <err.h>
#include <errno.h>
#include <linux/in.h>
#include <netdb.h>

void main(void)
{
   int s, fromlensize;
   char b[0]="";
   struct hostent *h;
   struct sockaddr_in localaddress,clientaddress;
   /* socket adres maken */
   s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
   if (s==-1) printf("socket: %s\n",strerror(errno));
   /* server socket binden aan lokaal adres */
   memset(&localaddress,0,sizeof(struct sockaddr_in));
   localaddress.sin_port=htons(0);
   localaddress.sin_family=AF_INET;
   localaddress.sin_addr.s_addr=htonl(0);
   if (-1==bind(s,&localaddress, sizeof(struct sockaddr_in)))
     printf("bind: %s\n",strerror(errno));
   /* data ontvangen */
   memset(&clientaddress,0,sizeof(struct sockaddr_in));
   fromlensize=sizeof(struct sockaddr_in);
   if (-1==recvfrom(s,b,0,0,&clientaddress,&fromlensize))
     printf("recv: %s\n",strerror(errno));
   printf("%s\n",b);
}

Communicatie vind enkel plaats wanneer een sendto in het ene proces en een recvfrom in het andere proces over dezelfde adressen praten. (Als het onderliggende netwerk broadcasting ondersteund kan een proces een broadcast paket uitsturen dat zal ontvangen worden door alle processen die een recvfrom doen op de juiste poort. Het adres voor de zender moet dan staan op een internet broadcast adres.)

Oef1: UDP Minesweeper

Schrijf een multi player minesweeper gebasseerd op de code voor een single player minesweeper. De bedoeling is dat meerdere spelers tegelijk op een slagveld kunnen ontmijnen. De spelers hun score gaat omhoog door een juist vakje te ontmijnen. Spelers vallen dood door op een mijn te tikken. Als het spel voorbij is worden de scores van al de spelers afgeprint.

Hou rekening hoe users connecteren, disconnecteren, waar het speelveld in geheugen gehouden wordt. Welk data protocol gehanteerd wordt. Wie welke errorchecks doet. Zet duidelijk voorhand op papier welke berichten verstaan worden en hoe de server van state naar state springt.

Oplossing Server

/* 
 *  client -> server
 *    byte 0: 'H'  (hitposition)
 *    byte 1-4: <x>
 *    byte 5-8: <y>
 *    -------------
 *    byte 0: 'J'   (joinrequest)
 *  server -> client
 *    byte 0: 'S'  (showposition)
 *    byte 1-4: <x>
 *    byte 5-8: <y>
 *    byte 9: <value>
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <termios.h>
#include <mntent.h>
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <curses.h>

#define XSIZ  0
#define YSIZ  0
#define MAXPLAYERS 0
static int playfield[XSIZ][YSIZ];
static int stayrunning = 1;
static int serversocket;

typedef struct sclient {
   struct sockaddr_in addr;
   int score;
   int status; /* 0 = niet actiev; 1 = actiev; 2 = duud */
} client;

static client clients[MAXPLAYERS];

int score=0;
/* -1: niet gemarkeerd als mijn, effectief mijn (onzichtbaar)
 * -2: niet gemarkeerd als mijn, leeg (onzichtbaar)
 * -3: gemarkeerd als mijn, effectief mijn (onzichtbaar)
 * -4: gemarkeerd als mijn, leeg (onzichtbaar)
 * 0: leeg vak, (zichtbaar)
 * 1 -> 8: x buren (zichtbaar)
 * 9: mijn (zichtbaar)
 */

int mine(int w)
{
   return w==9 || w==-1 || w==-3;
}

int countmines(int x, int y)
{
   int answer = 0;
   assert(x>=0);
   assert(y>=0);
   assert(x<XSIZ);
   assert(y<YSIZ);
   if (mine(playfield[x-1][y-1])) answer++;
   if (mine(playfield[x-1][y])) answer++;
   if (mine(playfield[x-1][y+1])) answer++;
   if (mine(playfield[x][y-1])) answer++;
   if (mine(playfield[x][y+1])) answer++;
   if (mine(playfield[x+1][y-1])) answer++;
   if (mine(playfield[x+1][y])) answer++;
   if (mine(playfield[x+1][y+1])) answer++;
   return answer;
}

void sendpion(int id, int x, int y)
{
   int aantal;
   char buf[6];
   buf[0]='S';
   *((int*)(buf+1))=x; 
   *((int*)(buf+5))=y;
   *((signed char*)(buf+9))=playfield[x][y];
   aantal=sendto(serversocket,buf,0,0,(struct sockaddr_in*)&(clients[id].addr),sizeof(struct sockaddr_in));
   assert(aantal!=-1);
}

void sendupdate(int x, int y)
{
   int i;
   for(i=0;i<MAXPLAYERS;i++)
     {
	if (clients[i].status==1)
	  {
	     sendpion(i,x,y);
	  }
     }
}

void sendfield(int id)
{
   int x, y;
   for(x=0;x<XSIZ;x++)
     for(y=0;y<YSIZ;y++)
       sendpion(id,x,y);
}

int hitposition(int x, int y)
/* nieuwe waarde van het vakje */
{
   if (x<=0) return 0;
   if (x>=XSIZ-1) return 0;
   if (y<=0) return 0;
   if (y>=YSIZ-1) return 0;
   if (playfield[x][y]>=0) return playfield[x][y];
   if (playfield[x][y]==-1 || playfield[x][y]==-3)  
     {
	playfield[x][y]=9;
	sendupdate(x,y);
     }
   if (playfield[x][y]==-2 || playfield[x][y]==-4)
     {
	playfield[x][y]=countmines(x,y);
	sendupdate(x,y);
     }
   if (playfield[x][y]>0) return playfield[x][y];
   hitposition(x-1,y);
   hitposition(x+1,y);
   hitposition(x,y-1);
   hitposition(x,y+1);
   hitposition(x-1,y-1);
   hitposition(x+1,y+1);
   hitposition(x+1,y-1);
   hitposition(x-1,y+1);
   return playfield[x][y];
}

void fillplayfield(int aantalmijnen, int aantaltrys)
{
   int x,y;
   srandom(time());
   assert(aantalmijnen>=0);
   for(x=0;x<XSIZ;x++)
     for(y=0;y<YSIZ;y++)
     playfield[x][y]=-2;
   while(--aantalmijnen>=0)
     {
	x=random()/(RAND_MAX/(XSIZ-2));
	y=random()/(RAND_MAX/(YSIZ-2));
	playfield[x+1][y+1]=-1;
     }
   while(--aantaltrys>=0)
     {
	x=random()/(RAND_MAX/(XSIZ-2));
	y=random()/(RAND_MAX/(YSIZ-2));
	hitposition(x+1,y+1);
     }
}

void showplayfield()
{
   int x,y,i;
   printf("\x1b\x5b\x48\x1b\x5b\x4a\n");
   for(y=1;y<YSIZ-1;y++)
     {
	for(x=1;x<XSIZ-1;x++)
	  {
	     if (playfield[x][y]==-1) printf("\x1b[1m\x1b[2;41m [] ");
	     if (playfield[x][y]==-2) printf("\x1b[1m\x1b[2;41m [] ");
	     if (playfield[x][y]==-3) printf("\x1b[1m\x1b[1;41m MM ");
	     if (playfield[x][y]==-4) printf("\x1b[1m\x1b[1;41m MM ");
	     if (playfield[x][y]==0) printf("\x1b[1m\x1b[7;41m    ");
	     if (playfield[x][y]==1) printf("\x1b[1m\x1b[7;41m 1  ");
	     if (playfield[x][y]==2) printf("\x1b[1m\x1b[7;41m 2  ");
	     if (playfield[x][y]==3) printf("\x1b[1m\x1b[7;41m 3  ");
	     if (playfield[x][y]==4) printf("\x1b[1m\x1b[7;41m 4  ");
	     if (playfield[x][y]==5) printf("\x1b[1m\x1b[7;41m 5  ");
	     if (playfield[x][y]==6) printf("\x1b[1m\x1b[7;41m 6  ");
	     if (playfield[x][y]==7) printf("\x1b[1m\x1b[7;41m 7  ");
	     if (playfield[x][y]==8) printf("\x1b[1m\x1b[7;41m 8  ");
	     if (playfield[x][y]==9) printf("\x1b[1m\x1b[1;41m XX \x1b[00m");
	  }
	printf("\n");
     }
   for(i=0;i<MAXPLAYERS;i++)
     {
	printf("%d\t",clients[i].score);
     }
   printf("\n");
}

void hitspot(int id, int x, int y)
{
   int newvalue;
   /* geen punten bij als reeds geweten is wat er ligt
    * wel pech als er reeds een mijn ligt */
   assert(x>0);
   assert(y>0);
   assert(x<XSIZ-1);
   assert(y<YSIZ-1);
   if (playfield[x][y]==9)
     clients[id].status=2;
   newvalue=hitposition(x,y);
   if (newvalue==9) 
     clients[id].status=2;
   else clients[id].score++;
   showplayfield();
}

void incomingmessages()
{
   struct sockaddr_in clientaddress;
   int i, count, x, y, fromlensize, aantal;
   char buf[6];
   /* data ontvangen */
   memset(&clientaddress,0,sizeof(struct sockaddr_in));
   fromlensize=sizeof(struct sockaddr_in);
   aantal=recvfrom(serversocket,buf,6,0,&clientaddress,&fromlensize);
   if (aantal==-1) return;
   /* is het een join-message ? */
   assert(aantal>=1);
   if (buf[0]=='J')
     {
	for(i=0;i<MAXPLAYERS;i++)
	  {
	     if (clients[i].status==0)
	       {
		  clients[i].addr=clientaddress;
		  sendfield(i);
		  clients[i].status=1;
		  return;
	       }
	  }
     }
   /* Gezien het eenvoudige protocol moet het nu een 'H'it zijn en geen 
    * 'J'oin ... */
   for(i=0;i<MAXPLAYERS;i++)
     {
	if (memcmp(&clients[i].addr.sin_addr,&clientaddress.sin_addr,sizeof(clientaddress.sin_addr))==0
	    && memcmp(&clients[i].addr.sin_port,&clientaddress.sin_port,sizeof(clientaddress.sin_port))==0)
	  break;
     }
   assert(i!=MAXPLAYERS);
   assert(aantal==9);
   assert(buf[0]=='H');
   x=*(int*)(buf+1);
   y=*(int*)(buf+5);
   hitspot(i,x,y);
}

void initserver()
{
   struct hostent *h;
   struct sockaddr_in serveraddr;
   int i;
   /* client table leeg maken */
   for(i=0;i<MAXPLAYERS;i++)
     {
	memset(&clients[i].addr,0,sizeof(struct sockaddr_in));
	clients[i].score=0;
	clients[i].status=0;
     }
   /* socket maken */
   serversocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (serversocket==-1) 
     {
	printf("socket: %s\n",strerror(errno));
	exit(1);
     }
   /* server socket binden aan lokaal adres */
   memset(&serveraddr,0,sizeof(struct sockaddr_in));
   serveraddr.sin_port=htons(0);
   serveraddr.sin_family=AF_INET;
   serveraddr.sin_addr.s_addr=htonl(0);
   if(-1==bind(serversocket,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr_in)))
     printf("bind: %s\n",strerror(errno));
   /* asynchroon */
   fcntl(serversocket,F_SETFL,O_NONBLOCK);
}

void main(void)
{
   fillplayfield(0,0);
   initserver();
   showplayfield();
   while(1)
     {
	incomingmessages();
     }
}

Oplossing Client

#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <termios.h>
#include <mntent.h>
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <curses.h>
#define XSIZ  0
#define YSIZ  0
static int playfield[XSIZ][YSIZ];
static int playerX=0;
static int playerY=0;
static int stayrunning = 1;
static struct sockaddr_in serveraddr;
static int localsocket;

/* -1: niet gemarkeerd als mijn, effectief mijn (onzichtbaar)
 * -2: niet gemarkeerd als mijn, leeg (onzichtbaar)
 * -3: gemarkeerd als mijn, effectief mijn (onzichtbaar)
 * -4: gemarkeerd als mijn, leeg (onzichtbaar)
 * 0: leeg vak, (zichtbaar)
 * 1 -> 8: x buren (zichtbaar)
 * 9: mijn (zichtbaar)
 */
void fillplayfield()
{
   int x,y;
   for(x=0;x<XSIZ;x++)
     for(y=0;y<YSIZ;y++)
       playfield[x][y]=-2;
}

void showplayfield()
{
   int x,y;
   printf("\x1b\x5b\x48\x1b\x5b\x4a\n");
   for(y=1;y<YSIZ-1;y++)
     {
	for(x=1;x<XSIZ-1;x++)
	  {
	     if (x==playerX && y==playerY)
	       {
		  if (playfield[x][y]==-1) printf("\x1b[1m\x1b[3;46m#[]#\x1b[00m");
		  if (playfield[x][y]==-2) printf("\x1b[1m\x1b[3;46m#[]#\x1b[00m");
		  if (playfield[x][y]==-3) printf("\x1b[1m\x1b[3;46m#MM#\x1b[00m");
		  if (playfield[x][y]==-4) printf("\x1b[1m\x1b[3;46m#MM#\x1b[00m");
		  if (playfield[x][y]==0) printf("\x1b[1m\x1b[3;46m####\x1b[00m");
		  if (playfield[x][y]==1) printf("\x1b[1m\x1b[3;46m#1##\x1b[00m");
		  if (playfield[x][y]==2) printf("\x1b[1m\x1b[3;46m#2##\x1b[00m");
		  if (playfield[x][y]==3) printf("\x1b[1m\x1b[3;46m#3##\x1b[00m");
		  if (playfield[x][y]==4) printf("\x1b[1m\x1b[3;46m#4##\x1b[00m");
		  if (playfield[x][y]==5) printf("\x1b[1m\x1b[3;46m#5##\x1b[00m");
		  if (playfield[x][y]==6) printf("\x1b[1m\x1b[3;46m#6##\x1b[00m");
		  if (playfield[x][y]==7) printf("\x1b[1m\x1b[3;46m#7##\x1b[00m");
		  if (playfield[x][y]==8) printf("\x1b[1m\x1b[3;46m#8##\x1b[00m");
		  if (playfield[x][y]==9) printf("\x1b[1m\x1b[3;46m#XX#\x1b[00m");
	       }
	     else
	       {
		  if (playfield[x][y]==-1) printf("\x1b[1m\x1b[2;44m [] ");
		  if (playfield[x][y]==-2) printf("\x1b[1m\x1b[2;44m [] ");
		  if (playfield[x][y]==-3) printf("\x1b[1m\x1b[1;44m MM ");
		  if (playfield[x][y]==-4) printf("\x1b[1m\x1b[1;44m MM ");
		  if (playfield[x][y]==0) printf("\x1b[1m\x1b[7;44m    ");
		  if (playfield[x][y]==1) printf("\x1b[1m\x1b[7;44m 1  ");
		  if (playfield[x][y]==2) printf("\x1b[1m\x1b[7;44m 2  ");
		  if (playfield[x][y]==3) printf("\x1b[1m\x1b[7;44m 3  ");
		  if (playfield[x][y]==4) printf("\x1b[1m\x1b[7;44m 4  ");
		  if (playfield[x][y]==5) printf("\x1b[1m\x1b[7;44m 5  ");
		  if (playfield[x][y]==6) printf("\x1b[1m\x1b[7;44m 6  ");
		  if (playfield[x][y]==7) printf("\x1b[1m\x1b[7;44m 7  ");
		  if (playfield[x][y]==8) printf("\x1b[1m\x1b[7;44m 8  ");
		  if (playfield[x][y]==9) printf("\x1b[1m\x1b[1;44m XX \x1b[00m");
	       }
	  }
	printf("\n");
     }
}

void markspot(int x, int y)
{
   assert(x>0);
   assert(y>0);
   assert(x<XSIZ-1);
   assert(y<YSIZ-1);
   if (playfield[x][y]>=0) return;
   if (playfield[x][y]==-1) playfield[x][y]=-3;
   else if (playfield[x][y]==-2) playfield[x][y]=-4;
   else if (playfield[x][y]==-3) playfield[x][y]=-1;
   else if (playfield[x][y]==-4) playfield[x][y]=-2;
   showplayfield();
}

void hitspot(int x, int y)
{
   char buf[6];
   buf[0]='H';
   *((int*)(buf+1))=x;
   *((int*)(buf+5))=y;
   sendto(localsocket,buf,9,0,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr_in));
}

void playermoved()
{
   if (playerX<1) playerX=1;
   if (playerY<1) playerY=1;
   if (playerX>XSIZ-2) playerX=XSIZ-2;
   if (playerY>YSIZ-2) playerY=YSIZ-2;
   showplayfield();
}

/* A: moveleft
 * S: moveright
 * W: up
 * Z: down
 * M: markeer als mijn
 * X: exit
 * spatie: hit the spot
 */
void rl_ttyset (int Reset)
{
  static struct termios old;
  struct termios new;
   if (Reset == 0)
     {(void) tcgetattr (0, &old);
      new = old;
      new.c_lflag &= ~(ECHO | ICANON);
      new.c_iflag &= ~(ISTRIP | INPCK);
      (void) tcsetattr (0, TCSANOW, &new);}
   else (void) tcsetattr (0, TCSANOW, &old);
   fcntl(0,F_SETFL,O_NONBLOCK);
   fcntl(1,F_SETFL,O_NONBLOCK);
   fcntl(2,F_SETFL,O_NONBLOCK);
}

void eventloop()
{
   int changed=0;
   struct sockaddr_in ditchit;
   int c,nr,x,y,v, fromlensize, aantal;
   char b, buf[6];
   while(stayrunning)
     {
	/* network check */
	changed=0;
	while ((aantal=recvfrom(localsocket,buf,6,0,&ditchit,&fromlensize))>0)
	  {
	     assert(buf[0]=='S');
	     assert(aantal==0);
	     x=*(int*)(buf+1);
	     y=*(int*)(buf+5);
	     v=*(signed char*)(buf+9);
	     playfield[x][y]=v;
	     changed=1;
	  }
	if (changed) showplayfield();
	/* keyboard check */
	c=0;
	nr=read(0,&c,1);
	if (nr==0) continue;
	changed=1;
	if (c=='q')
	  {  playerX--;
	     playermoved();}
	if (c=='s')
	  {  playerX++;
	     playermoved();}
	if (c=='z')
	  {  playerY--;
	     playermoved();}
	if (c=='w')
	  {  playerY++;
	     playermoved();}
	if (c=='x')
	  stayrunning=0;
	if (c=='m')
	  markspot(playerX,playerY);
	if (c==' ')
	  hitspot(playerX,playerY);
     }
}

void initclient()
{
   struct hostent *h;
   struct sockaddr_in localaddress;
   int i, aantal;
   /* socket maken */
   localsocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (localsocket==-1) printf("socket: %s\n",strerror(errno));
   /* socket binden aan een lokaal adres */
   memset(&localaddress,0,sizeof(struct sockaddr_in));
   localaddress.sin_port=htons(0);
   localaddress.sin_family=AF_INET;
   h=gethostbyname("7.0.0.1");
   memcpy(&localaddress.sin_addr,h->h_addr,h->h_length);
   if (-1==bind(localsocket,(struct sockaddr_in*)&localaddress,sizeof(struct sockaddr_in)))
     printf("bind: %s\n",strerror(errno));
   /* asynchroon zetten */
   fcntl(localsocket,F_SETFL,O_NONBLOCK);
   /* serveraddress instellen */
   memset(&serveraddr,0,sizeof(struct sockaddr_in));
   serveraddr.sin_port=htons(0);
   serveraddr.sin_family=AF_INET;
   h=gethostbyname("4.4.9.3");
   memcpy(&serveraddr.sin_addr,h->h_addr,h->h_length);
   /* joinen */
   aantal=sendto(localsocket,"J",1,0,(struct sockaddr_in*)&serveraddr,sizeof(struct sockaddr_in));
   if (aantal!=1)
     {
	printf("%d: %s\n",aantal, strerror(errno));
	assert(aantal==1);
     }
}

void main(void)
{
   rl_ttyset(0);
   fillplayfield();
   initclient();
   eventloop();
   rl_ttyset(1);
}

http://werner.yellowcouch.org/
werner@yellowcouch.org