Hi,
I am trying to open a socket to communicate with a local server
running on my machine on port 8088, to send back and forth simple
Lisp text. I am using Allegro CL, although I am almost certain that
whatever I'm doing wrong here is a universal error on all Lisps :)
I tried the following snippet, based on what I read in
<http://www.cl.cam.ac.uk/ailanguages/allegro5/socket.htm>:
[1] CL-USER(2): (setf s (socket:make-socket :remote-host "localhost"
:connect :active :remote-port 8088))
#<MULTIVALENT stream socket connected from localhost/56894 to
localhost/8088 @ #x7150cf42>
When I try to write to the server, this happens:
[1] CL-USER(3): (format s "(concept? simple-test)\r\n")
NIL
(I also tried (format s "(concept? simple-test)~C~C" #\Linefeed #\Newline))
[1] CL-USER(4): (read-char-no-hang s)
NIL
..(read s) and (read-char s) both hang.
When I tried what seems to be the equivalent of the above in Python[1],
it worked, so I know the server is not at fault. I'm sure I'm
misunderstanding something simple about the socket interface. Could
someone please explain what I'm doing wrong?
Thanks a lot,
--
Yarden Katz <····@underlevel.net> | Mind the gap
[1] I used the following bit of Python:
>>> from socket import *
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s.connect(('127.0.0.1', 8088))
>>> s.send('(concept? simple-test)\r\n')
24
>>> s.recv(1024)
':answer 1 "NIL" ""\n'
--
Yarden Katz <····@underlevel.net> | Mind the gap
[Meant to send the answer here, sorry Yarden]:
Check out FORCE-OUTPUT and related functions. Allegro is probably
buffering the stream.
--
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
Matthew Danish <·······@andrew.cmu.edu> writes:
> [Meant to send the answer here, sorry Yarden]:
>
> Check out FORCE-OUTPUT and related functions. Allegro is probably
> buffering the stream.
I looked at
<http://www.lispworks.com/reference/HyperSpec/Body/f_finish.htm> and
from what I can tell, force-output is the most relevant function as
you suggest. However, (force-output s) did not fix it. It evaluates
to nil and reading/writing to the stream results in the same
behavior. Do you have any other ideas? I'm quite lost on this.
Thanks a lot!
--
Yarden Katz <····@underlevel.net> | Mind the gap
Yarden Katz <····@underlevel.net> writes:
> Matthew Danish <·······@andrew.cmu.edu> writes:
>
>> [Meant to send the answer here, sorry Yarden]:
>>
>> Check out FORCE-OUTPUT and related functions. Allegro is probably
>> buffering the stream.
>
> I looked at
> <http://www.lispworks.com/reference/HyperSpec/Body/f_finish.htm> and
> from what I can tell, force-output is the most relevant function as
> you suggest. However, (force-output s) did not fix it. It evaluates
> to nil and reading/writing to the stream results in the same
> behavior. Do you have any other ideas? I'm quite lost on this.
Consider trying something like:
(with-output-to-string (s)
(format s "i present ~a" "a simple test\n"))
Chris
Yarden Katz wrote:
>
> I looked at
> <http://www.lispworks.com/reference/HyperSpec/Body/f_finish.htm> and
> from what I can tell, force-output is the most relevant function as
> you suggest. However, (force-output s) did not fix it. It evaluates
> to nil and reading/writing to the stream results in the same
> behavior. Do you have any other ideas? I'm quite lost on this.
>
What does the code look like on the server side?
A no-op client I use in teaching Lisp looks more or less exactly like
your code:
;-*- Mode: Common-lisp; Package: cl-user; -*-
(in-package :cl-user)
(defvar cs472-port 5720)
(defun client-sock ()
(let ((socket-stream nil) from-server from-user
server-host)
(format t "Name or IP address of server machine: ")
(setq server-host
(string-trim " \t" (read-line *standard-input*)))
(unwind-protect
(progn
(setq socket-stream (acl-socket:make-socket
:connect ':active
:remote-host server-host
:remote-port cs472-port))
(format t "Found server~%")
(loop
(format t "Input a string: ")
(setq from-user (read-line *standard-input*))
(format t " [Sending to server]~%")
(format socket-stream "~a~%" from-user)
(force-output socket-stream)
(format t " [Reading from server]~%")
(setq from-server (read-line socket-stream))
(format t "From server: ~a~%" from-server)))
(progn
(format t "Abort!~%")
(cond (socket-stream
(close socket-stream)))))))
You type a string on the client side, which sends it to the server,
which prompts for a string and sends it back. To illustrate that you
can talk to anyone, the server is in Java, which doesn't require forcing
anything (but I seem to recall does require a \n before it actually
sends anything). If you wrote the server in Lisp, it probably would
have to force-output when sending back to the client.
import java.net.*;
import java.io.*;
import java.util.*;
public class Serv_sock
{
static int cs572_port = 5720;
public static void main(String[] argv) throws IOException
{
String Dataset = null;
try
{
InetAddress local_addr = InetAddress.getLocalHost();
String host_name = local_addr.getHostName();
String host_addr = local_addr.getHostAddress();
byte[] raw_addr = local_addr.getAddress();
System.out.println("Server host name = " + host_name);
System.out.println("Server IP address = " + host_addr);
int int_addr = 0;
for (int i=0;i<=3;i++)
{
System.out.println("raw[" + i + "] = " + raw_addr[i]);
int_addr = (int_addr << 8) | raw_addr[i];
}
System.out.println("Server integer address = " + int_addr);
}
catch (Exception e)
{
System.out.println("Can't get server host data\n because of "
+ e);
}
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(cs572_port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + cs572_port);
System.exit(1);
}
while(true)
{
System.out.println("Waiting.....");
Socket clientSocket = null;
PrintWriter out_to_client = null;
BufferedReader in_from_client = null;
BufferedReader
in_from_user
= new BufferedReader(new InputStreamReader(System.in));
try
{
clientSocket = serverSocket.accept();
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
String from_cli = null, from_user = null;
try
{
out_to_client
= new PrintWriter(clientSocket.getOutputStream(), true);
in_from_client
= new BufferedReader
(new InputStreamReader(clientSocket.getInputStream()));
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
try
{
System.out.println(" [Reading from client]");
while ((from_cli = in_from_client.readLine()) != null)
{
System.out.println("From client: " + from_cli);
System.out.println("Input a string: ");
try
{
from_user = in_from_user.readLine();
System.out.println(" [Sending to client]");
out_to_client.println(from_user);
}
catch(IOException e)
{
System.err.println
("Can't read from user; not sending to client");
}
}
}
catch(IOException e)
{
System.err.println("Can't communicate with client");
}
out_to_client.close();
in_from_client.close();
clientSocket.close();
}
}
}
Before the to-and-fro interchange gets going, the server tells you its
IP address, which you can tell to the client if you don't want to type a
symbolic hostname.
-- Drew McDermott
Yarden Katz <····@underlevel.net> writes:
> I am trying to open a socket to communicate with a local server
> running on my machine on port 8088, to send back and forth simple
> Lisp text. I am using Allegro CL, although I am almost certain that
> whatever I'm doing wrong here is a universal error on all Lisps :)
Well, socket interfacess are implementation-specific.
> [1] CL-USER(3): (format s "(concept? simple-test)\r\n")
> NIL
>
> (I also tried (format s "(concept? simple-test)~C~C" #\Linefeed #\Newline))
>
> [1] CL-USER(4): (read-char-no-hang s)
> NIL
>
> ..(read s) and (read-char s) both hang.
Wild guess: Maybe (force-output s) helps?
hth
Henrik