0

I'm trying to build a server client application using jetty. I have setup a jetty server and configured websockets. Sending text messages works fine between client and server. But how binary data as inputstream could be sent from client endpoint. I cannot find any snippets regarding websocket client. Below is what i have tried

ServerEndPoint:

   @OnMessage
   public void handleBinaryMessage(InputStream input, Session session) {

       logger.info("onMessage::inputstream");

       try {

        byte[] buffer = new byte[2048];
        try (OutputStream output = session.getBasicRemote().getSendStream())
        {
            int read;
            while ((read = input.read(buffer)) >= 0)
                output.write(buffer, 0, read);
        }

    } catch (IOException e) {
      e.printStackTrace();
    }

ClientEndpoint:

@OnOpen 
public void onOpen(Session s) throws IOException {
  logger.info("Client Connected ... " + s.getId());
  this.session=s;

  session.getBasicRemote().sendText("Ping from client");

  // size of the file 200~500MB
  File source= new File("/tmp/Setup.exe");

  try(InputStream input = new FileInputStream(source)) {


              session.getAsyncRemote().sendObject(input);


            }

}        

Any help is appreciated

EDIT:

I have modified clientendpoint and serverendpoint. Trying to send data as chunks but the zip file is partial or sometimes even very smaller than source file.

source size : 1.5gb after writing data from buffer using stream : 20kb

@ClientEndpoint

   private static void sendFileToRemote(File source) throws FileNotFoundException, IOException {
        // TODO Auto-generated method stub
            Session session=null;
            final WsClient wc = new WsClient("ws://localhost:2714/events/","test");

            session=wc.getSession();

             try (
                        InputStream inputStream = new FileInputStream(source);

                    ) {


                    byte[] chunk = new byte[102400];
                    int chunkLen = 0;
                    while ((chunkLen = inputStream.read(chunk)) != -1) {

                        session.getAsyncRemote().sendBinary(ByteBuffer.wrap(chunk, 0, chunkLen));
                    }

                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }

             }

@serverendpoint

@ServerEndpoint("/events/")
public class EventListener {
    static Logger logger = Logger.getLogger(Initservice.class.getName());
   private OutputStream os=null; 
@OnOpen
    public void Init(Session session) throws FileNotFoundException {

        this.user_session = session;
        logger.info("onOpen:: server" + session.getId());     

        this.os = new FileOutputStream(new File("/tmp/silicon_test.zip"));
        logger.info("instantiate zip files");

    }

@OnMessage
    public void onMessage(Session session, ByteBuffer byteBuffer) throws IOException {
        try {

          os.write(byteBuffer.get());

        } catch(Exception e) {
            close();
            logger.log(Level.SEVERE,"Exception occured in onMessage :: ", e);
            throw e;
        }
    }
}

1 Answers1

1

The code in your ServerEndpoint looks like it should work fine, however in your ClientEndpoint you are only sending text data to the ServerEndpoint and this can only be read by a server onMessage method configured to receive text messages.

Instead of using session.getRemoteEndpoint().sendText(...) you should use the method session.getRemoteEndpoint().sendBinary(...). This will send the data in binary frames instead of text frames and you will be able to receive it in your servers handleBinaryMessage method.

As for the session.getAsyncRemote().sendObject(input), to make this work you will also need to provide an Encoder.Binary or Encoder.BinaryStream in order to send the object as binary data.

Edit:

WebSocket is a message based protocol and you are sending your data from the file over multiple websocket messages. You could use session.getBasicRemote().sendBinary(ByteBuffer, boolean) to send partial messages and send all the data in the same message.

Or you could try something like this code which may be simpler.

try (InputStream inputStream = new FileInputStream(source))
{
    try (OutputStream sendStream = session.getBasicRemote().getSendStream())
    {
        inputStream.transferTo(sendStream);
    }
}
Lachlan
  • 356
  • 1
  • 7
  • Thanks for the favour. I have tried sending data as chunks, this time i got the response in serverendpoint but the data is partial or even very smaller. i have mentioned changes in the post – Logesh Elangovan May 04 '20 at 16:55
  • I have updated the answer with some additional info on sending the data all in the same websocket message. – Lachlan May 05 '20 at 11:41
  • Thanks a lot @Lachlan. I have transfered the file as chunks. But still confused about **session.getBasicRemote().getSendStream()**. If i use this at my serverEndPoint. Where the file will be saved?. May be at current directory? – Logesh Elangovan May 08 '20 at 17:57
  • The send stream sends the data as a websocket message to the other websocket endpoint, not to save it to a file, you would use this on the client to send the file. Read the javadoc. If you want to write to a file you can still use the FileOutputStream you are using. – Lachlan May 09 '20 at 00:14