[comp.unix.questions] Sockets

jmay@bbn.com (Jason May) (07/29/88)

Thanks to those people that sent me information in response to
my question concerning sockets a couple of weeks back.  For
the interest and edification of those and any others, here is
a working example of socket use.

There are two files here.  I don't know how to make my own shar
files, so I've just stuck the files at the end of this message.
The two files are a server and a client - the server will
accept connections from up to MAXCLIENTS different clients and can carry
on conversations with all of them and not get them confused.
The code is not the most beautiful imaginable, and there are lots
of other things that could be done here, but this stuff at least
works (under Ultrix, that is, and presumable BSD and others).

Jason
(jmay@alexander.bbn.com)


=====================
server.c
=====================

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define TRUE 1
#define FALSE 0

#define PORT 0x1234
#define ADDRSIZE sizeof (SOCK)
#define MAXCLIENTS 4

typedef struct sockaddr_in SOCK;
SOCK server;

typedef struct {
    SOCK *client;
    char *text;
} MESSAGE;

int create_server ();
MESSAGE *server_recv (/* sd */);
int server_send (/* sd, client, message */);
void done_server ();
int find_client (/* client * */);
int find_free_client ();

int numclients = 0;
SOCK client[MAXCLIENTS+1];
MESSAGE message;


void main()
{
    int sd;
    int flag = TRUE, ok = TRUE;
    int i;
    MESSAGE *msg;
    int clinum;

    bzero (client, ADDRSIZE * MAXCLIENTS);

    if ((sd = create_server ()) == -1)
	exit (1);

    while (flag) {
	msg = server_recv (sd);
	ok = TRUE;

	if ( (clinum = find_client (msg->client)) == -1)
	  if ( (clinum = find_free_client ()) == -1) {
	      printf ("No space for a new client; %d clients allocated\n",
		      numclients);
	      ok = FALSE;
	      bcopy (msg->client, &(client[MAXCLIENTS]), ADDRSIZE);
	      server_send (sd, MAXCLIENTS, "End");
	      numclients++;
	  }
	  else {
	      bcopy (msg->client, &(client[clinum]), ADDRSIZE);
	      printf ("Server: Allocating slot %d to client.\n", clinum);
	  }

	if (ok) {
	    printf ("Server: Rcvd '%s' from client %d [%d.%d.%d.%d, %x]\n",
		    msg->text, clinum, msg->client->sin_addr.s_net,
		    msg->client->sin_addr.s_host, msg->client->sin_addr.s_lh,
		    msg->client->sin_addr.s_impno, msg->client->sin_port);
	    flag = server_send (sd, clinum, msg->text);
	}
    }	
    done_server (sd);
}


int create_server ()
{
    int sd;

    if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
	perror ("Server: socket");
	return (-1);
    }

    bzero (server, ADDRSIZE);
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons (PORT);

    if (bind (sd, &server, ADDRSIZE) == -1) {
	perror ("Server: bind");
	return (-1);
    }

    return (sd);
}


MESSAGE *server_recv (sd)
int sd;
{
    static SOCK cli;
    int addrlen = ADDRSIZE;
    static char text[100];
    int clinum;

    bzero (text, sizeof (text));

    if (recvfrom (sd, text, sizeof (text), 0, &cli, &addrlen) == -1) {
	perror ("Server: recv");
	return (NULL);
    }

    message.client = &cli;
    message.text = text;

    return (&message);
}

int server_send (sd, clinum, msg)
int sd;
int clinum;
char *msg;
{
    if (sendto (sd, msg, strlen (msg), 0, &(client[clinum]), ADDRSIZE) == -1) {
	perror ("Server: sendto");
	return (-1);
    }

    if (strcmp (msg, "End") == 0) {
	client[clinum].sin_family = 0;
	numclients--;
	if (numclients == 0)
	  return (FALSE);
	else
	  return (TRUE);
    }
    else
      return (TRUE);
}


void done_server (sd)
int sd;
{
    close (sd);
}


int find_client (cli)
SOCK *cli;
{
    int i;

    for  ( i=0; (bcmp (&(client[i]), cli, ADDRSIZE) != NULL) &&
	   (i < MAXCLIENTS); i++ );

    if (i >= MAXCLIENTS)
      return (-1);
    else
      return (i);
}


int find_free_client ()
{
    int i;

    for ( i=0; (client[i].sin_family != 0) && (i < MAXCLIENTS); i++ );

    if (i >= MAXCLIENTS)
      return (-1);
    else {
	numclients++;
	return (i);
    }
}

=====================================
client.c
=====================================

#include <stdio.h>
#include <sys/types.h>
#include <curses.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 0x1234
#define HOST "serverhost"	/* replace this */
#define ADDRSIZE sizeof (struct sockaddr_in)

int setup_sockets (/* hostname, port, server */);
int mysend (/* sd, server, msg */);
char *myrecv (/* sd, server */);
void client_done ();

struct sockaddr_in server;

void main ()
{
    int sd;
    char to_server[80];
    char *from_server;
    int flag = 1;

    if ( (sd = setup_sockets (HOST, PORT, &server)) == -1)
      exit (1);

    while (flag) {
	printf ("Enter: ");
	gets (to_server);
	if (mysend (sd, &server, to_server) != -1)
	  printf ("Client: Received '%s' from server\n",
		  from_server = myrecv (sd, &server));
	if (strcmp (from_server, "End") == NULL)
	  flag = 0;
    }
    client_done (sd);
}


int setup_sockets (hostname, port, server)
char *hostname;
int port;
struct sockaddr_in *server;
{
    int sd;
    struct hostent *hp;

    if ((hp = gethostbyname (hostname)) == 0) {
	perror ("Client: gethostbyname");
	return (-1);
    }

    bzero (server, ADDRSIZE);
    server->sin_family = AF_INET;
    server->sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
    server->sin_port = htons (port);
    
    if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
	perror ("socket:");
	return (-1);
    }
    return (sd);
}


int mysend (sd, server, msg)
int sd;
struct sockaddr_in *server;
char *msg;
{
    int count;

    if ((count = sendto (sd, msg, strlen (msg), 0, server, ADDRSIZE)) == -1) {
	perror ("Client: sendto");
	return (-1);
    }
    return (count);
}


char *myrecv (sd, server)
int sd;
struct sockaddr_in *server;
{
    int addrlen = ADDRSIZE;
    static char msg[100];
    int msglen;

    if (recvfrom (sd, msg, msglen, 0, server, &addrlen) == -1) {
	perror ("Client: recv");
	return (NULL);
    }
    msg[msglen] = 0;
    return (msg);
}


void client_done (sd)
int sd;
{
    if (shutdown (sd, 2) == -1) {
	perror ("Client: shutdown");
	exit (1);
    }

    close (sd);
}

cookson@mbunix.mitre.org (Cookson) (02/03/90)

I'm trying to learn how to use sockets for interprocess communication,
both on a single machine, and across a net.  Can anyone recomend a
good source for me to read?

Thanks in advance
Dean

cookson@mbunix.mitre.org

gt0178a@prism.gatech.EDU (BURNS,JIM) (07/21/90)

A while back, Patrick Spinler posted a sockets program that he was having
trouble with and asked for email replies. I sent him the mail below asking
for his results and it bounced. Would appreciate email OR a post
(especially if YOU bounce).

From MAILER-DAEMON@prism.gatech.edu Fri Jul 20 22:00:12 1990
Return-Path: <MAILER-DAEMON@prism.gatech.edu>
Received: by hydra.gatech.edu (5.61/3.1)
	id AA06120; Fri, 20 Jul 90 21:50:48 -0400
Date: Fri, 20 Jul 90 21:50:48 -0400
From: MAILER-DAEMON@prism.gatech.edu (Mail Delivery Subsystem)
Subject: Returned mail: Cannot send message for 5 days
Message-Id: <9007210150.AA06120@prism.gatech.edu>
To: gt0178a@prism.gatech.edu
Status: RO

   ----- Transcript of session follows -----
421 att1.mankato.msus.edu.cether... Deferred: Connection timed out during user open with att1.mankato.msus.edu

   ----- Unsent message follows -----
Return-Path: <gt0178a@prism.gatech.edu>
Received: by hydra.gatech.edu (5.61/3.1)
	id AA15925; Sun, 15 Jul 90 21:55:38 -0400
Date: Sun, 15 Jul 90 21:55:38 -0400
From: gt0178a@prism.gatech.edu (BURNS,JIM)
Message-Id: <9007160155.AA15925@prism.gatech.edu>
To: pspinler@att1.mankato.msus.edu
Subject: Re: question about using sockets on sysVr3

pspinler@att1.mankato.msus.edu (Patrick J. Spinler):
> I am attempting to learn to use sockets, however, I am evidently
> creating a protocal error of some sort, and have no real idea where to
> start looking.  If some kind soul would please tell me why I'm getting
> an EINVAL error on my call to bind(), I would be very grateful.  I'm

Did you ever get an answer to your question, and can you forward same to
me? I would prefer working code and an explanation of the changes.

I got past your bind error by commenting out the bcopy just before, but
then the connection never established, and timed-out.

				Thanx, Jim Burns
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

gt0178a@prism.gatech.EDU (BURNS,JIM) (07/21/90)

in article <11639@hydra.gatech.EDU>, gt0178a@prism.gatech.EDU (BURNS,JIM) says:
  A while back, Patrick Spinler posted a sockets program that he was having
  trouble with and asked for email replies. I sent him the mail below asking
  for his results and it bounced. Would appreciate email OR a post
  (especially if YOU bounce).

Sorry - Please ignore this message - I posted it to the wrong group.
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

ciancarini-paolo@cs.yale.edu (paolo ciancarini) (04/22/91)

I would like to pass a socket from a process to another;
the two processes in general are unrelated
(they could even be on different machines, say sharing an NSF FS).

To be a little more concrete, I have a concurrent server
that uses a connection-oriented protocol
using the sequence: socket/bind/listen/accept/fork.
I have other processes, not created by the server, that would like to get
the particular socket obtained after accept.

So, is it possible to pass such a socket among unrelated processes?

Please answer by E-mail. I will summarize if there is any interest
(and any answer!).

Paolo Ciancarini

wayne@jahangir.UUCP (wayne) (05/24/91)

	I am just starting to expirement with sockets. I have a small program
below which I cannot get to work for some reason. I took it almost verbatum
from W. Richard Stevens book "UNIX Network Programming" 

	What happens is the client and server fail to connect for some reason.
Can anyone out there tell me what I am doing wrong?

	My hardware is a MIPS Magnum 3000. 

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (05/24/91)

In article <556@jahangir.UUCP> wayne@jahangir.UUCP (wayne) writes:
>
>
>	I am just starting to expirement with sockets. I have a small program
>below which I cannot get to work for some reason. I took it almost verbatum
>from W. Richard Stevens book "UNIX Network Programming" 
>
>	What happens is the client and server fail to connect for some reason.
>Can anyone out there tell me what I am doing wrong?
>
>	My hardware is a MIPS Magnum 3000. 

Sure. The problem is line 79 of /u/wayne/foo/bar/socket/test.c. Put a space
before the comment at the end of that line, and your program will work :-)

Seriously, why don't you post what your code to the net so people can see 
exactly WHAT it is. We're not mindreaders, ya know. 


			-Kartik


--
internet% ypwhich

subbarao@phoenix.Princeton.EDU -| Internet
kartik@silvertone.Princeton.EDU (NeXT mail)  
SUBBARAO@PUCC.BITNET			          - Bitnet

wayne@jahangir.UUCP (wayne) (06/29/91)

	Here's on for all you sockets fans out there. I have stream
sockets. One process creates and binds to the socket. Another process
connects to the socket.

	If something bad happens and both processes exit without closing
the socket, is there a way to close the socket. The process that bound
the socket has not properly closed it. And the reading process has died.
In effect leaving a orphaned socket.

	Can you get rid of this thing short of rebooting?

	

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (06/29/91)

In article <564@jahangir.UUCP> wayne@jahangir.UUCP (wayne) writes:
> 	Here's on for all you sockets fans out there. I have stream
> sockets. One process creates and binds to the socket. Another process
> connects to the socket.
> 	If something bad happens and both processes exit without closing
> the socket, is there a way to close the socket. The process that bound
> the socket has not properly closed it. And the reading process has died.
> In effect leaving a orphaned socket.

When a process dies, all its descriptors are closed. If every process
that had the socket open suddenly dies, the socket is closed.

I suspect that you're working with UNIX-domain sockets, and what you're
seeing is the useless socket file left after the server dies. You can
just remove it. If the socket was for meant for just that connection,
the server should remove the bound filename immediately after accept().
In any case it should make an effort to catch those ``bad'' things
happening and remove the socket before it exits.

---Dan