Question

I am trying to send RDF/XML from a Client to a Server using sockets in Java. When I send the information the Server program hangs and does not receive the info unless I close the Socket or OutputStream on the Client side. Even if I flush the OutputStream on the Client-side the Server does not receive the data unless I close the Socket/Stream. I would like to send the information without closing the socket. Here is some example code for the Client (using Sesame):

import java.io.*;
import java.net.*;
import org.openrdf.rio.*;
import org.openrdf.rio.helpers.*;
import org.openrdf.model.URI;
import org.openrdf.model.Model;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.Statement;
import org.openrdf.model.impl.*;
import org.openrdf.model.vocabulary.*;
public class SimpleRDFClient {
    private Socket socket = null;
    public static void main(String[] args) {
        new SimpleRDFClient(args[0],Integer.parseInt(args[1])).launch();
    }
    public SimpleRDFClient(String host, int port) {
        try {
            socket = new Socket(host,port);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    public void launch() {
        try {
            OutputStream out = socket.getOutputStream();
            BufferedOutputStream dos = new BufferedOutputStream(out);
            Model model = new LinkedHashModel();
            ValueFactory factory = new ValueFactoryImpl();
            URI clive = factory.createURI("http://www.site.org/cliveAnderson");
            Statement st = factory.createStatement(clive, RDF.TYPE, FOAF.PERSON);
            model.add(st);
            Rio.write(model,dos,RDFFormat.RDFXML);
            dos.flush();
            //Some other stuff
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}   

And the Server Handler:

import java.io.*;
import java.net.*;
import org.openrdf.rio.*;
import org.openrdf.rio.helpers.*;
import org.openrdf.model.*;
import org.openrdf.model.impl.*;

public class SimpleRDFSHandler implements Handler {
    public void handleConnection(Socket socket) {
        Model model = null;
        try {
            InputStream in = socket.getInputStream();

            model = Rio.parse(in,"www.blah.com",RDFFormat.RDFXML);

            for (Statement st: model) {
                System.out.println(st);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

The problem seems to come from the Rio.parse() method hanging (I think because it does not know when the input ends). I get a similar problem when I use the Jena api in a similar way, i.e. using Model.write(outputstream,format) and Model.read(inputstream,format) instead of Rio. I have looked at the source and the javadoc for ages but can't solve the problem. I think it must be something simple I have misunderstood. Any ideas?

Was it helpful?

Solution

I don't think this is in any way a Jena/Sesame specific issue but rather a Java issue around your use of sockets. Is there actually a practical reason you want to not close the socket?

I don't see why this would ever be advisable unless you want to continuously post data and process it as it is received on the server side? If this is the case both Jena and Sesame have APIs that specifically allow you to control what happens to data as it parsed in so that you aren't reliant on your read calls from completing before you process the data.

Also why use sockets, both Sesame and Jena have comprehensive HTTP integration which is much easier to use and deploy than rolling your own socket based server and clients.

The Ugly Hacky Solution

If you really must do this then there is a workaround but it is somewhat horrid and fragile and I would strongly recommend that you do not do this.

On the client side after you write the data write a sequence of bytes that indicate end of stream. On the server side wrap the socket stream with a custom InputStream implementation that recognizes this sequence and stops returning data when it is seen. This should allow the Jena/Sesame code which is expecting the stream to finish to function correctly.

The sequence of bytes need to be carefully chosen such that it won't naturally occur in the data.

To be honest this is a terrible idea, if your aim is to continuously post data this won't really solve your problem because then you'll just be leaking sockets server side unless you put the server side socket handling code in a while (true) loop which is likely another bad idea.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top