0

EDIT: The code below throws no exception but has no output and hangs. It should output "Test message". In main(), we start a thread that's given a server socket listening on a random port. The main thread the tries to connect and communicate with the ServerSocket on that same random port, but is apparently failing. Why?

public class IntraProcSockTest {
private static int port;

private class Listener extends Thread {
    public Listener() {
    }

    public void run() {
        try {
            ServerSocket serverSocket = new ServerSocket(0);
            port = serverSocket.getLocalPort();
            Socket socket = serverSocket.accept();

            BufferedReader in;
            String fromClient;

            in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));

            while ((fromClient = in.readLine()) != null) {
                System.out.println("From client: " + fromClient);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public IntraProcSockTest() {
    new Listener().start();
}

public static void main(String[] args) {
    new IntraProcSockTest();

    try {
        Thread.sleep(5000);
        Socket socket = new Socket("localhost", port);
        PrintWriter socketOut = new PrintWriter(socket.getOutputStream());

        socketOut.println("Test message");
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
Rooster
  • 1,267
  • 3
  • 15
  • 23

2 Answers2

4

A process can connect to a socket created by itself, there is no problem. Show us the code that throws an exception and/or more details about the exception.

First of all, be careful not to specify a local port for the client socket (the one connecting to the other which is listening). Let the OS choose a random port. Remember that any socket is identified by four elements (remote host, local host, remote port, local port), if you bind both the server socket and the client socket on the same local port, let it be 4498, both sockets are defined as follows: (localhost, localhost, 4498, 4498) and this doesn't work. I suspect this might be your problem.
To avoid such problems, client sockets are often bound to a random port, chosen by the OS. Show us your code, expecially the part in which the client sockets gets created and connects to the server socket.

And about IPC, it is not always bad to use sockets as an inter-process or even intra-process communication technique. The performance is worse, obviously, and you might loose some code readability, but your software will be easily portable to a network (distributed) application. It's up to your plans, it's not like IPC sockets == bad.

gd1
  • 11,300
  • 7
  • 49
  • 88
  • Ah the second paragraph is indeed my problem. So binding the client and server sockets on the same port on localhost isn't working for me. – Rooster Nov 14 '11 at 06:58
  • Sure, but this is absolutely not a problem, since you can let the O.S. bind the socket to any free local port it can find. Just be sure to specify the remote port, otherwise you won't connect as well. The difference between local and remote port is always a bit confusing. For server sockets the local port is important, for client sockets just care about the remote one. – gd1 Nov 14 '11 at 07:02
  • Question about random ports: when a server chooses a random port, how does the client know which port to connect to it's socket it on? – Rooster Nov 14 '11 at 07:02
  • OK, in fact no server socket is bound to a random local port. For server sockets the local port is important, for client sockets just care about the remote one, the local one is random. – gd1 Nov 14 '11 at 07:03
  • As an exception, in IPC sockets you often use random ports for servers as well. But I don't want to confuse you: I find it more useful if you fix your code. :) – gd1 Nov 14 '11 at 07:05
  • Could you give a simple example you think would work in my situation (with remote port specified I guess)? Just the server's ports and the clients ports really (in the same process). – Rooster Nov 14 '11 at 07:18
  • If I were in your shoes, I'd instantiate a ServerSocket, binding it to a **random port** (see the docs, I think `new ServerSocket(0)` should do the trick), get the randomly chosen port via `getLocalPort()` and store it in a variable, call it `port`. Then, I'd instantiate a new client Socket with `new Socket("localhost", port)` **on another thread**. The client socket will be given a random local port as well, but you don't want to know it. Just don't care. You have a full duplex IPC mechanism... Hope it helps :) – gd1 Nov 14 '11 at 13:11
  • Even simpler you can call new Socket(**null**, port) and it will connect to localhost skipping name lookup, and to avoid Microsoft Windows Firewall warnings about the listening socket, you can bind it to loopback only: this is a bit more sophisticated. But first try to make it work this way. – gd1 Nov 14 '11 at 13:19
  • I put your example to work in my above edit, but as you see I'm still having trouble. Perhaps further help should be put in a new answer. I appreciate it. – Rooster Nov 14 '11 at 20:15
2

To create a Socket connection in one thread you can.

ServerSocket ss = new ServerSocket(0); // open a random free port.
Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s = ss.accept();
ss.close();

final byte[] bytes = "Hello World!".getBytes();
final OutputStream out = c.getOutputStream();
out.write(bytes.length);
out.write(bytes);


final DataInputStream in = new DataInputStream(s.getInputStream());
int len = in.read();
final byte[] b = new byte[len];
in.readFully(b);
System.out.println(new String(b));

c.close();
s.close();

If all you want is IPC within a Process, a socket is not the fastest or simplest way to go. Try using a Pipe (NIO) or PipeInput/OutputStream (IO). Its faster and simpler.

Pipe pipe = Pipe.open();
SinkChannel sink = pipe.sink();
SourceChannel source = pipe.source();

or

PipedOutputStream output = new PipedOutputStream();
PipedInputStream input = new PipedOutputStream(output);  

BTW: You can connect a client and server Socket in the same thread, however

Using an Exchanger is 10x faster, and using a ring buffer is faster again.

If you want convenience, using an ExecutorService is the best way to deleagte work to a background pool of threads. This can still perform millions of tasks per second.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • +1 You are right, even if I find more readable and straightforward using blocking queues. However, he asked how to do it with sockets, lacking some knowledge about how sockets work :) It has been a way to learn something, like always in S.O..... – gd1 Nov 14 '11 at 13:14