barshay@stars.reston.unisys.com ( Unisys) (05/02/90)
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.
ash@aaii.oz.au (Andrew Hodgson) (05/07/90)
barshay@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