I have a server-client architecture where the client sends an XML to the server who reads it and generates a PDF out of it and sends that back to the client.
On the client side:
JAXBElement<Xml> xml = ...
Socket sock = ...
Marshaller marshaller = ...
marshaller.marshal(xml, sock.getOutputStream());
sock.shutdownOuput();
Meanwhile on the server side:
ServerSocket server = ...
Socket client = server.accept();
Unmarshaller unmarshaller = ...
// client.isClosed() -> false
JAXBElement<Xml> xml =
(JAXBElement<Xml>)) unmarshaller.unmarshall(client.getInputStream());
// client.isClosed() -> true
Pdf pdf = new Pdf(xml);
client.getOutputStream().write(pdf.toBytes());
// "socket is closed" IOException is thrown
If I don't unmarshall the client's InputStream (on the server side) and just send back a dummy PDF then everything's goes smoothly. So, I have to assume that the Unmarshaller closes the InputStream it is given, thus implicitly closing the client Socket ruining my day...
Any idea on solving this?
The class XMLEntityManager calls close on the InputStream.
You can use a FilterInputStream to avoid a close() call of the underlying stream.
Subclass FilterInputStream and override the close() method with an empty body:
public class MyInputStream extends FilterInputStream {
public MyInputStream(InputStream in) {
super(in);
}
#Override
public void close() {
// do nothing
}
}
Then change your unmarshall() call to
JAXBElement<Xml> xml =
(JAXBElement<Xml>)) unmarshaller.unmarshall(new MyInputStream(client.getInputStream()));
So the JAXB framework still calls close() on the stream, but it's now filtered out by your own stream instance and the socket stream remains open.
If you don't want to explicitly override an InputStream in your code like vanje suggest, Apache commons-io provide a implementation that acheive this:
take a look at :
CloseShieldInputStream
Related
I want to implement a full-duplex communication through java socket and can enter information through the front-end page.
After the two parties establish a connection through the socket, the front-end can call the url interface to enter the message to be sent, but now that I have implemented the socket_send method on the back-end through threads, I can only enter message in the console. If I want to implement the interface, the socket_send method requires the ObjectOutputStream type to call the writeObject method, but in the interface, I cannot get the ObjectOutputStream.
I want to know how can I enter the message I want to send in the socket_send thread through the front-end page?
class Server_send implements Runnable{
private final Socket socket;
Server_send(Socket socket){
this.socket=socket;
}
#Override
public void run() {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
while(true){
System.out.print("Please input the msg to be sent:");
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
JSONObject obj = new JSONObject();
obj.put("type","chat");
obj.put("msg",str);
oos.writeObject(obj);
oos.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ObjectOutputStream will try to use the default Java serialization mechanism, which you don't want anywhere except Java itself. The best library for JSON serialization is Jackson if you need one.
Try to use this template:
. . .
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
// Jackson's ObjectMapper is here
bos.write(new ObjectMapper().writeValueAsBytes(msgObject));
// also you can send plain strings
bos.write("hello".getBytes());
. . .
I'd like to do something similar to the example posted in restlet's site (first applicaiton) - with one difference:
I want to stream data - not use primitive types - using an interface.
I want to define some kind of an interface between the client and the server, stream data between them and let restlet handle transmit the data seamlessly.
Example of what I have in mind:
interface Streaming {
InputStream startStream(String streamId);
}
When the client invokes a call, it starts reading from the inputstream. The server receives the call and starts providing the stream by creating an inputstream (for example, a video file, or just some raw data). Restlet should be reading from the inputstream on the server side and provide the data as an inputstream on the client side.
Any idea how can I achieve this? A code sample or link to one would be great. Thanks.
Below's an example code of what I learned so far - an interface with streaming capavilities and a client-server streaming example.
I haven't yet added parameters to the interface and it's only download - no upload yet.
Interface:
public interface DownloadResource {
public ReadableRepresentation download();
}
Interface with protocol: (separation between logic and technology):
public interface DownloadResourceProtocol extends DownloadResource {
#Get
#Override
public ReadableRepresentation download();
}
Client:
ClientResource cr = new ClientResource("http://10.0.2.2:8888/download/");
cr.setRequestEntityBuffering(true);
DownloadResource downloadResource = cr.wrap(DownloadResourceProtocol.class);
// Remote invocation - seamless:
Representation representation = downloadResource.download();
// Using data:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
IOUtils.copy(representation.getStream(), byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
Log.i("Byte array: " + Arrays.toString(byteArray));
Server:
public class DownloadResourceImpl extends ServerResource implements DownloadResourceProtocol {
#Override
public ReadableRepresentation download() {
InputStreamChannel inputStreamChannel;
try {
inputStreamChannel = new InputStreamChannel(new ByteArrayInputStream(new byte[]{1,2,3,4,5,6,7,8,9,10}));
return new ReadableRepresentation(inputStreamChannel, MediaType.ALL);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
Configuration:
public class SampleApplication extends Application {
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/download/", DownloadResourceImpl.class);
return router;
}
}
Not sure this addresses your problem completely, but one approach is to create a thread that streams data back to the client using ReadableRepresentation and a Pipe.
Create a pipe:
Pipe pipe = Pipe.open();
Create a representation like this:
ReadableRepresentation r = new ReadableRepresentation(pipe.source(), mediatype);
Start a separate thread that writes batches of bytes to the pipe like this:
pipe.sink().write(ByteBuffer.wrap(someBytes));
return the representation to the client.
I have to serialize an object and send it from a httpserver
i already know how to send a string from the server to the client,but i don't know how to send a object
So i have this code :
public class Test {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/test", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = "This is the response";
//this part here shows how to send a string
//but i need to send an object here
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
so i tried to search google but no results,and i tried to change the code (mechanically without knowing well what im doing as im not used to HttpServer's in java)
this way :
SendResponse obj = new SendResponse();
ObjectOutputStream objOut = new ObjectOutputStream();
t.sendResponseHeaders(200, objOut);
objOut.writeObject(obj);
objOut.close();
but eclipse shows me an error which tells me that the ObjectOutputStream() constructor is not visible and that httpExchange is not applicable for the arguments (int,ObjectInputStream)
Do you have any idea how i can fix this ?
Thank you in advance for your help !
You have accesible the constructor with one OutputStream as parameter
ObjectOutputStream objOut = new ObjectOutputStream( the http or any other output stream here );
The constructor of ObjectOutputStream sends some header bytes and the constructor of ObjectInputStream expects these header bytes. You should either create a new ObjectOutputStream and a new ObjectInputStream for every object, or create only one ObjectOutputStream and ObjectInputStream for all the objects.
A more simple alternative could be google gson It´s easy to use and it converts a java class to json string and the inverse way too.
After some hours of trying different things
you have just to replace the
t.sendResponseHeaders(200, objOut);
with
t.sendResponseHeaders(200,0);
as mentioned by user cyon on this question
I am working on a server/client communication program and I am stuck at a problem. When I try to send messages from my client side it won't work properly. After initializing the server, I connect the client and that is successful. When I try to send messages from the client, the server won't receive them. After I close the client connection, the server receives all of the messages I attempted to send earlier. The following class is what I am using:
public class ServerSender extends Thread
{
private DataOutputStream out = new DataOutputStream(socket.getOutputStream());
private Scanner kb = new Scanner(System.in);
public void run()
{
while(true)
{
try
{
out.writeUTF(kb.nextLine());
out.flush();
} catch(IOException e) { System.out.println("error"); }
}
}
}
Any help would be much appreciated, thanks.
DataOutputStream doesn't have a buffer to flush, so your diagnosis is incorrect. However you need to be aware that writeUTF() writes a format that only DataInputStream.readUTF() can read. If you're trying to write lines you have the wrong API: try BufferedWriter.write()/.newLine().
I have a server-client pair and I want to create a listener on the client end for new server responses. I am not sure how to do this, right now I can only interact in a direct synchronous way.
Here is the server:
public class TestServer {
public static void main(String[] args) throws Exception {
TestServer myServer = new TestServer();
myServer.run();
}
private void run() throws Exception {
ServerSocket mySS = new ServerSocket(4443);
while(true) {
Socket SS_accept = mySS.accept();
BufferedReader myBR = new BufferedReader(new InputStreamReader(SS_accept.getInputStream()));
String temp = myBR.readLine();
System.out.println(temp);
if (temp!=null) {
PrintStream serverPS = new PrintStream(SS_accept.getOutputStream());
serverPS.println("Response received: " + temp);
}
}
}
}
As you can see, it sends a response when it gets one. However in general I won't be sure when other servers I use send responses, so I would like to create an asynchronous listener (or at least poll the server for a response every half-second or so).
Here is what I'm trying on the client end:
protected static String getServerResponse() throws IOException {
String temp;
try {
BufferedReader clientBR = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
temp = clientBR.readLine();
} catch (Exception e) {
temp = e.toString();
}
return temp;
}
And just for reference, yes, sending over data from client to server works fine (it System.out's the data correctly). However, when I call the above function to try and retrieve the server response, it just hangs my application, which is an Android application in case that's relevant.
What I want from a function is just the ability to ask the server if it has data for me and get it, and if not, then don't crash my damn app.
On the client side create a ConnectionManager class which will handle all the socket I/O. The ConnectionManager's connect() method will create and start a new thread which will listen for server responses. As soon as it will receive a response it will notify all the ConnectionManager's registered listeners. So in order to receive asynchronously the server responses you will have to register a listener in ConnectionManager using its register(SomeListener) method.
Also, you can have a look at JBoss Netty which is an asynchronous event-driven network application framework. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.