inter-process-communications

Andrew Hodgson ash at aaii.oz.au
Mon May 7 10:43:05 AEST 1990


barshay at stars.reston.unisys.com ( Unisys):
> I have a Lucid Lisp process running on a Sun Workstation that needs to be
> able to communicate with a C process running on either the same Sun
> Workstation or another workstation on the same network.  Does anybody have
> any suggestions?  What I really am hoping for is the way to use sockets
> from Lucid Lisp.

It is simple enough using the a bit of 'C' code and the foreign function
interface.

Here is the 'C' code I use

cut it out put it in socket.c and run
cc -c socket.c

move socket.o to socket_sparc.o or socket_68000.o depending on machine type.

I haven't tried it on a 386i but I presume it would work.

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

/*
 * Connect to a socket by service name or port number.
 * If port is 0, service will be used.
 * Returns a file descriptor for the socket.
 */
int
connect_to_socket(hostname, service, port)
char	*hostname;
char	*service;
u_int	port;
{
    struct sockaddr_in	remote_addr;	/* remote inet socket address	*/
    struct servent	*serv;		/* returned by getservbyname()	*/
    struct hostent	*host;		/* returned by gethostbyname()	*/
    int			sock;

    if (strlen(service) <= 0)
	service = NULL;
    if ((host = gethostbyname(hostname)) == NULL) {
	perror("gethostbyname");
	return (-1);
    }
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	perror("socket");
	return (-1);
    }
    if (service != NULL) {
	if ((serv = getservbyname(service, "tcp")) == NULL) {
	    if (port <= 0) {
		fprintf(
		    stderr,
		    "Unknown serv %s/tcp. No default port given\n",
		    service
		);
		return(-1);
	    }
	    remote_addr.sin_port = htons((u_short) port);
	}
	else
	    remote_addr.sin_port = serv->s_port;
    }
    else
	remote_addr.sin_port = htons((u_short) port);
    remote_addr.sin_family = host->h_addrtype;
    bcopy(host->h_addr, &remote_addr.sin_addr, host->h_length);
    if (connect(sock, &remote_addr, sizeof(remote_addr)) < 0)  {
	perror("connect");
	return (-1);
    }
    return(sock);
}

Here is the lisp code I use.

#+SUN
(in-package 'cv)

(export '(#+SUN connect-to-socket open-socket))

#+SUN
(def-foreign-function (connect-to-socket
		       (:return-type	:signed-32bit))
  (host-name 	:simple-string)
  (service	:simple-string)
  (port-number	:unsigned-32bit)
  )

#+SUN
(load-foreign-files #+SPARC "socket_sparc.o"
		    #+MC68000 "socket_68000.o"
		    )

;;; OPEN-SOCKET
;;;
;;; Return a lisp stream connected to a socket on
;;; host with the given service name or number.
;;;
#+SUN
(defun open-socket (host
		    service
		    &key input output (auto-force T) (default-port 0)
		    &aux fd)
  (when (numberp service)
	(setq default-port service)
	(setq service ""))
  (if (minusp (setq fd (connect-to-socket host
					  service default-port)))
      nil
      (let* ((in (if input fd nil))
	     (out (if output fd nil)))
	    (make-lisp-stream :input-handle in
			      :output-handle out
			      :auto-force auto-force))))

So to open a connection to the 'C' process simply do

(setq socket-stream (open-socket
				"XXX.reston.unisys.com" 3000
				:input t
				:output t
		))

then use it as a normal lisp stream. 

One warning. Since the the auto-force flag is by default true on the
stream every output operation will actually go out on the net. So when
doing a lot of output on the stream make sure you have a 

	(with-buffered-output ...

around the code or you will get lots of small packets going out on your
net. Eg tepri will output a packet with 1 char it it. (Expensive and
slow).

As an example we got 10X improvement in throughput simply by putting
with-buffered-output around one critical function



More information about the Comp.sys.sun mailing list