I'm following this tutorial and I'm putting the returned data on console log in Chrome. Here is my code on client side:
$(document).ready(function() {
//check for browser support
if(typeof(EventSource)!=="undefined") {
var source = new EventSource("URL/sse");
//detect message receipt
source.addEventListener("message", function(e) {
console.log(e.data);
}, false);
source.addEventListener("open", function(e) {
console.log("Connection was opened.");
}, false);
source.addEventListener("error", function(e) {
if (e.readyState == EventSource.CLOSED) {
console.log("Connection lost.");
}
}, false);
}
else {
// No support
}
});
The data is ok. When I access the webpage, my console log is opening and closing the connection every 3 seconds:
mypage.js:39 Connection was opened.
mypage.js:15 [{"John":"1","Doe":"2"}]
mypage.js:44 Error - Connection lost.
// 3 seconds
mypage.js:39 Connection was opened.
mypage.js:15 [{"John":"1","Doe":"2"}]
mypage.js:44 Error - Connection lost.
// 3 seconds
mypage.js:39 Connection was opened.
mypage.js:15 [{"John":"1","Doe":"2"}]
mypage.js:44 Error - Connection lost.
...
Here is my server-side code:
#Singleton
#Path("/sse")
public class SSEResource {
#GET
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getServerSentEvents() {
final EventOutput eventOutput = new EventOutput();
new Thread(new Runnable() {
#Override
public void run() {
try {
final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
eventBuilder.name("message");
final String myString = getData.toString(); // Some data from db
eventBuilder.data(String.class, myString);
final OutboundEvent event = eventBuilder.build();
eventOutput.write(event);
} catch (Exception e) {
throw new RuntimeException("Error when writing the event.",
e);
} finally {
try {
eventOutput.close();
} catch (IOException ioClose) {
throw new RuntimeException(
"Error when closing the event output.", ioClose);
}
}
}
}).start();
return eventOutput;
}
}
From what I understand, the connection should remain open until the client decided to close it. What am I doing wrong? Is that correct?
Your server code is closing the EventOutput.
try {
eventOutput.close();
} catch (IOException ioClose) {
throw new RuntimeException(
"Error when closing the event output.", ioClose);
}
This causes the client to reconnect and the process starts again.
I'm not 100% sure what you are doing. If you want to send more data in the thread, you need to not close the EventOutput.
According to the specification you can send a HTTP 204 No Content response code to prevent the client from reconnecting, I'm not sure how to do this using Jersey SSE though. I was searching for the answer when I came across this question.
In your case you could send a message that causes the client to close the connection, or prevents it from reconnecting.
Related
an app in PC using JAVA io.socket which will sends json to a server device ESP8266on TCP on LAN network
when you are connected and when disconnect sequence is executed from java it self everything is ok .
java is client and device is server , when device cuts the connection (here lets use Hercules on localhost) the java program will not being noticed and when i try to write with outputstreamwriter it dose not trig an exception , exception will be executed after at least two writes to socket after the server is being disconnected and the last two writes which was not being received by server will return success! in java. i have read other programmers use a byte send to see if connection is still alive . the same problem is there too . if i send two write each 20 seconds time in between its going to be 60 seconds before java realize server is disconnected and if i send every 1 second is going to be a lot of ATcommand interrupts for nothing .
here is my code:
public boolean Write(String data){
System.out.println("StartSending");
if(TESocket.Connected)
{
Thread write = new Thread(new Runnable() {
#Override
public void run() {
try
{
outputStreamWriter.write(data);
outputStreamWriter.flush();
}
catch (IOException e)
{
TESocket.Connected=false;
System.out.println("Faild");
System.out.println(e.getCause());
}
}
});
write.start();
return true;
}
else
{
System.out.println("Not Connected");
return false;
}
}
The TESocket is class which handles Socket using Runnable and Connected is a static boolean since there is just one socket at a time here is the connect method
public boolean Connect(){
Thread connect = new Thread(new Runnable() {
#Override
public void run() {
try {
socket= new Socket("127.0.0.1",Integer.parseInt(port));
if(socket.isConnected())
{
inputStreamReader = new InputStreamReader(socket.getInputStream());
outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
TESocket.Connected=true;
System.out.println("Connected");
}
} catch (IOException e) {
System.out.println("Faild to Connect");
e.printStackTrace();
}
}
});
connect.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(TESocket.Connected)
return true;
else
return false;
}
how can i be noticed if server is out of reach with immediately after sending the write? or is there eny event for noticing that ? maybe some king of asynchronous socket? like it was in QT (Signal Slot for Disconnect)
well By reading method and setting a timeout solved this problem , thanks to reading some post
in read if i am still connected and not receiving any data time out will be thrown which bring me back to the first lie of the while loop
if i receive data i will be bigger than zero which reader will read data and flag the rec=true so the disconnect sequence dose not take in place
if i don't receive any data and timeout dose not occurs the rec=false and exception will not be thrown so the program will o to disconnect routine
setting the timeout to 1 millisecond makes it real-time (proportional to my work) in deadline detection
public boolean Read()
{
if (TESocket.Connected)
{
try {
socket.setSoTimeout(1000);
} catch (SocketException e) {
System.out.println("Problem Timeout");
e.printStackTrace();
}
Thread read = new Thread(new Runnable() {
#Override
public void run() {
int i;
boolean rec=false;
while (true)
{
char[] reader = new char[250];
try {
//while(!inputStreamReader.ready());
i=inputStreamReader.read(reader);
if(i>0) {
System.out.println(reader);
rec=true;
}
// Thread.sleep(2500);
if(!rec)
{
System.out.println("Disconnected");
TESocket.Connected=false;
inputStreamReader.close();
outputStreamWriter.close();
socket.close();
break;
}
rec=false;
}
catch (IOException e)
{
System.out.println("Connected");
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
read.start();
}
return true;
}
I'm having problems with a simple java socket client: the connection is established properly and both server and client receive and send data. But some time message receiving and sending 2 or 4 times. I have used following library https://github.com/socketio/socket.io-client-java
initialisation of socket in Application class
public static Socket getSocket() {
if (mSocket == null) {
try {
IO.Options opts = new IO.Options();
String[] opt1 = new String[1];
opt1[0] = "websocket";
opts.transports = opt1;
//opts.reconnection = true;
//opts.reconnection = false;
mSocket = IO.socket(BuildConfig.SOCKETURL);
} catch (URISyntaxException e) {
Log.i("SOCKET", "info>>" + e.getMessage());
throw new RuntimeException(e);
}
}
return mSocket;
}
Code of receiving event in Activity class
socket?.on("newMessage", object : Emitter.Listener {
override fun call(vararg args: Any?) {
// logic after call back goes here
}
}
}
})
Problem is 'newMessage' event is triggered multiple times sometimes, in onDestroy() event is socket?.off("newMessage") unregistered.
I am working on a chat app in Java and so far everything works all right except that when a client disconnects and a message is send by other client this error pops out:
java.net.SocketException: Software caused connection abort: socket write error
at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:110)
at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
at java.base/java.io.DataOutputStream.write(DataOutputStream.java:107)
at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:401)
at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
at com.terkea/com.terkea.system.server.ClientThread.run(ClientThread.java:65)
at java.base/java.lang.Thread.run(Thread.java:835)
This is my server Thread:
#Override
public void run() {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
while (!socket.isClosed()) {
try {
String input = in.readUTF();
if (Message.fromJSON(input).getUserName().equals("REGISTER")) {
Message specialMessage = Message.fromJSON(input);
specialMessage.setUserName("SERVER");
Client test = Client.fromJSON(specialMessage.getMessage());
test.setIp(socket.getInetAddress().toString());
test.setListening_port(String.valueOf(socket.getPort()));
specialMessage.setMessage(Client.toJSON(test));
input = Message.toJSON(specialMessage);
}
for (ClientThread thatClient : server.getClients()) {
DataOutputStream outputParticularClient = new DataOutputStream(thatClient.getSocket().getOutputStream());
outputParticularClient.writeUTF(input);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
and the Client:
public void createClient() {
try {
socket = new Socket(getHost(), portNumber);
DataInputStream in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
Message registerclient = new Message("REGISTER", Client.toJSON(getClient()));
out.writeUTF(Message.toJSON(registerclient));
new Thread(() -> {
while (!socket.isClosed()) {
try {
if (in.available() > 0) {
String input = in.readUTF();
Message inputMessage = Message.fromJSON(input);
if (inputMessage.getUserName().equals("SERVER")) {
System.err.println(Client.fromJSON(inputMessage.getMessage()));
allClientsConnected.add(Client.fromJSON(inputMessage.getMessage()));
} else {
chat.add(inputMessage);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
The error corresponds to outputParticularClient.writeUTF(input);
My goal is to get rid of this error and also if possible could anybody tell me a way to check when a client disconnects? I've found some similar questions over here and their solution was to check if (socket.getInputStream().read()!=-1)
but when I do that the whole program freezes and the GUI stops working.
You may want to look into expanding upon your special message functionality, and instead of using the username to pass "REGISTER" use something like messageType in order to do so. This way you can configure handlers based on type to do a number of things. For example things like:
MessageType { REGISTER, UNREGISTER, READ_RECEIPT, ... }
You can then have things like:
RegisterHandler {}
UnregisterHandler{}
and eventually expand them to have some features like facebook/whatsapp (/ICQ haha):
TypingHandler {} // Other user gets a message saying that I am typing to them
From here, you can implement the UNREGISTER to do what you want. Like the first comment says, you should catch the SocketException and manually unregister that client so it doesn't happen anymore. But you should also try to pre-emptively send an
{
messageType: UNREGISTER,
from: Client1
to: server|null,
data: {}
}
so that your server can remove it before the exception occurs. This would also let you handle Offline messages, if that's something you're interested in.
So I have a Websocket Session that reads information from a server. However if I cut off the information that it's receiving completely, after about a minute or so it will stop receiving new information, and won't do anything, even when the output from the server is turned back on.
I thought that the WebSocketContainer method
setDefaultMaxSessionIdleTimeout(Long time)
would fix my issue, so I set it to
container.setDefaultMaxSessionIdleTimeout(86400000L);
which I thought would mean it will continue running up to 1 day of inactivity.
However this is not the case, it stops after just a minute of inactivity. Below is the code I'm using, maybe someone can let me know what I'm doing wrong:
public void run(String... args) throws Exception {
log.info("Starting...");
log.info("-- API URL: {}", apiUrl);
log.info("-- API Token: {}", apiToken);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.setDefaultMaxSessionIdleTimeout(86400000L);
ClientEndpointConfig config = ClientEndpointConfig
.Builder.create()
.configurator(new CustomConfigurator(apiToken))
.build();
try {
session = container.connectToServer(ConsumerClient.class, config, URI.create(apiUrl));
} catch (DeploymentException de) {
log.error("Failed to connect - DeploymentException:", de);
} catch (IOException ioe) {
log.error("IOException:", ioe);
}
if (this.session == null) {
throw new RuntimeException("Unable to connect to endpoint.");
}
log.info("Max Idle Timeout: " + session.getMaxIdleTimeout());
log.info("Connected.");
log.info("Type \"exit\" to cancel.");
log.info("...Waiting for data...");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input;
try {
do {
input = br.readLine();
if (!input.equals("exit")) {
this.session.getBasicRemote().sendText(input);
}
} while (!input.equals("exit"));
} catch (IOException e) {
log.error("IOException:", e);
}
}
I'm fairly new to websockets so I may be completely misunderstanding something, but I hope someone will be able to point me in the right direction. Thanks in advance!
Can you try setMaxIdleTimeout(0) on the session?
According to the setDefaultMaxSessionIdleTimeout docs:
The value may be overridden on a per session basis using Session.setMaxIdleTimeout(long)
Context:
The following AsyncTask for an android application sends and receives so called Request objects from a server.
If the user makes changes to his stuff in the app, new request objects get generated and added to the synchronization queue. If he then hits the sync-button the AsyncTask is created and executed with his requests as parameters.
The handler finally takes all answers and sets the neccessary consequences in the database. He then finally updates the UI by calling one single method on the UI thread (onPostExecute).
public class RequestSender extends AsyncTask<Request, Void, Boolean>{
// Server data
private String host;
private int port = 1337;
private Socket socket;
private AnswerHandler handler;
public RequestSender(AnswerHandler handler) {
this.host = "hostNameHere";
this.handler = handler;
}
/**
* This method gets started as asynchronous task when you call .run()
* #return
*/
#Override
protected Boolean doInBackground(Request... requests) {
return sendAndReceive(requests);
}
private boolean sendAndReceive(Request... requests) {
boolean isConnected = this.initSocket();
if(isConnected) {
this.send(requests);
this.waitForAnswer();
} else {
handler.setRequests(requests);
}
return isConnected;
}
/**
* Tries to open a socket on the android device to a specified Host
*/
private boolean initSocket() {
try {
SocketAddress sockaddr = new InetSocketAddress(host, port);
socket = new Socket();
socket.connect(sockaddr, 5000);
return true;
} catch (UnknownHostException e) {
System.err.println("Unknown Host in initSocket()");
} catch (IOException e) {
System.err.println("Connection timed out");
}
return false;
}
/**
* Tries to send a request to the server
* #param request
*/
public void send(Request... request) {
if(socket != null) {
try {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(request);
out.flush();
} catch (IOException e) {
System.err.println("Couldn't write to socket in RequestSender");
}
}
}
/**
* Waits for the answer from the server and reports the result in the handler
*/
private void waitForAnswer() {
try {
socket.setSoTimeout(5000);
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Request[] answers = (Request[]) in.readObject();
socket.close();
handler.setRequests(answers);
} catch (StreamCorruptedException e) {
System.err.println("Failed to open stream from server");
} catch (IOException e) {
System.err.println("Failed to read answers from server");
} catch (ClassNotFoundException e) {
System.err.println("Failed to read class from server");
}
}
#Override
protected void onPostExecute(Boolean a) {
handler.updateUI();
}
}
Now my Problem:
The whole thing works without any problem for a few times (It depends on the goodwill of my phone how many times), but then it seems like the task gets stuck somewhere without giving me any error message on System.err.
Restarting the app solves the problem and it works again without any problem.
I already read that AsyncTasks get executed on one single thread since Honeycomb. I set a timeout on open socket and read in, so a stuck task should terminate after this timeout.
Is there any problem with my code and could you imagine a solution for this?
Recently I face this problem and after debugging a lot and brain storming for a week I finally got the bug.
Ok lets do some homework.
Process to send/receive data
Establish a connection. Let assume connectToServer() is a function that physically connects the device to the server.
The socket/TCP part. In your case you have doInbackground(), in which you are calling initSocket() to initiate a socket connetion.
In real world scenario when you request a connection to a server it takes some time, may be a one or two seconds. So you should wait for that time before initiating a socket connection request. If a socket request send before a connection then it goes to lock state and releases after the default time out is finished which make it stuck.
Programming scenario
connectToServer();
// wait for 1 or 2 second.
initSocket();
Sample code
/* Function to check whether we are physically connected to the server or not */
private boolean isConnEstablished(){
WifiInfo connInfo = mManager.getConnectionInfo();
return mManager.isWifiEnabled() && connInfo.getNetworkId() != -1 && connInfo.getIpAddress() != 0;
}
private void initSocket() {
boolean scanning = true;
int tryCount = 5; // we trying for 5 times
try {
while (scanning && tryCount > 0) {
try {
if (isConnEstablished()) {
try{
Thread.sleep(500);
}catch (InterruptedException e){
Log.e("Yo", "sleep-error");
}
tConnection = new Socket(host, port);
scanning = false;
Log.e(getClass().getName(), "Socket connection established");
}else {
throw new ConnectException();
}
} catch (ConnectException e) {
Log.e(getClass().getName(), "connecting again...");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Log.e(getClass().getName(), "System sleep-error: " + ex.getMessage());
}
}
tryCount--;
}
}