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