javawebsocketjettyjava-websocketjsr356

javax.websocketclient : how to send large binary data from clientendpoint to serverendpoint


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;
        }
    }
}

Solution

  • 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);
        }
    }