How can I detect when a java socket (client socket or server socket) is closed & execute a callback method when close event occurs?
I don't want to use exception handling to do this. I'm seeking for a solution such as event handler or callback method, something like this(this is just an imaginary code!) :
Socket s = new Socket(ip, port);
s.addSocketClosedHandler(new SocketClosedHandler(){
#Override
public void onSocketClosed(SocketClosedEvent e){
...
}
});
Do you want to handle the event that you close the socket or the event that 'the other side' closes the socket? In the first case, you could subclass Socket and add handlers called when you call 'close'.
In the latter case, the problem is that this is not automatically detected and that reliably detecting it can be difficult and depends on the protocol being used to communicate over the socket. See e.g. this SO question. In general you will have to take action to determine whether the socket has in fact been closed by the other side. If so, you will need to take action. Whatever action you take, you could make sure it also calls callback handlers you registered for that action.
Why can't you use exception handling? This is the way the API is designed.
The only other way to do this is to design your protocol so that the other side sends something before it is about to close so that a local call to close() can be made first - but this won't always work, such as if the connection is closed unexpectedly.
Related
The canonical way of using a Selector in java NIO is :
regist the a ServerSocketChannel with the SelectionKey.OP_ACCEPT event type .
invoke select method (which block the thread)in a loop method
then when a OP_ACCEPT event happened , and the relative AcceptEventHandler is invoked to accept a SocketChannel
then regist the accepted SocketChannel with the SelectionKey.OP_READ event type.
when a read event happend , the ReadEventHandler handle the inputs and then regist the SocketChannel with a SelectionKey.OP_WRITE event type.
My question is, why don't register three event type at once at the beginning? Does the sequence make any sense?
The canonical way of using a Selector in java NIO is:
No it isn't. See below.
why don't register three event type at once at the beginning?
Because you can't. You don't have the accepted channel until you call accept(), and you don't do that until you have registered OP_ACCEPT and had it fire, and you can't register the accepted channel for anything until you have it.
does the sequence make any sense?
Nothing else would make sense.
NB you don't register OP_WRITE until you've encountered a short or zero-length write. The reason is that it is almost always ready, so the strategy is simply to write when you have something to write, and only use OP_WRITE to tell you when it becomes possible to write again after a short write (which means the socket send buffer was full).
I'm going to try to add something to the conversation.
A ServerSocketChannel can only accept() new connections. OP_READ / OP_WRITE won't do you anything there. I'm pretty sure you can add them but they will just be ignored because the ServerSocketChannel's only responsibility is to accept() remote SocketChannel.
Once you accept() and get a new SocketChannel; you want to listen to OP_READ first. If you listen to OP_WRITE then most likely you will get the OP_WRITE returned to you every single time you call select() and that will consume lots of resources.
You only want to listen to OP_WRITE when you tried to write some data to the SocketChannel and not all the data was written.
I have a question about a connect() call of a TCP socket implementation. What does it mean for a connect() call to be non-blocking. The connect() call does a three-way handshake with some other socket, by sending a syn, waiting for a SYNACK and then send an ACK. The connect() call also returns true if the connection succeeded or false if it did not succeed.
If the call is non-blocking then I guess that means that the connect should return immediately, even if it is still waiting for a SYNACK, but in that case it can never return false when it fails to connect because by then it already returned.
So my questions:
- What does it mean for a connect() call to be non-blocking.
- How does a connect() call achieve this? Is this only possible using threads?
- Im simulating a tcp stack in java, could you give a simplified example of how the non-blocking version would look? I included a sketch of what I think the blocking version roughly looks like (more psuedo code than actual java):
public boolean connect(IpAddress dst, int port){
// create a syn packet and send it
ipLayer.send(.....,<synpacket>);
try{
// wait for a synack and store it in receive_packet
ipLayer.receive(...., receivePacket,<timeout>);
} catch( TimeoutException e ){
// timed out.
return false;
}
// use information from a receivePacket to create an ack-packet then send it.
ipLayer.send(<ackpacket>);
return true;
}
So my questions: - What does it mean for a connect() call to be non-blocking.
Exactly what you said. It does not wait for network traffic.
How does a connect() call achieve this? Is this only possible using threads?
If you define threads broadly enough, then the answer is yes. But typically it's not implemented with what we normally consider threads. It just tells the network stack to make the connection. The network stack sends out packets and respond to things like timer and network interrupts to keep the process going.
Im simulating a tcp stack in java, could you give a simplified example of how the non-blocking version would look? I included a sketch of what I think the blocking version roughly looks like (more psuedo code than actual java):
Just don't wait for a reply. Determine if it's possible to send a SYN. If not, return an error. If so, send the SYN. If you need a thread to wait for the reply for some reason, then you'll have to create a thread to do that.
But something about your code is fundamentally broken. You either need a thread in both the non-blocking case and the blocking case or neither. It's impossible to need a thread in one and not the other. If you need a thread in the non-blocking case, it's only because you can't run your TCP engine without a thread. But then if you don't have one in the blocking case, there's no way to run your TCP engine. What happens when the other side sends packets? Say the other side sends a RST -- how will your code reply to it?
You need to look at the actual Java API. A non-blocking connect consists of two operations: a connect(), which sends the SYN and initiates the handshake, and a finishConnect(), which tests for completion of the handshake. The handshake is asynchronous, and when it completes it triggers an OP_CONNECT for the Selector.
There is no 'return false' from any connect operation in Java, but there are exceptions.
I have a Swing client which has a connect and cancel button so it can attempt connection to the server or end a current connection. I'm trying to make it so the client can connect to the server, end the connection and then connect to the server again multiple times.
My understanding is that typically when a client and server end a connection regardless of who ends it the client closes its streams and socket. Obviously then, they cannot be reused for another connection attempt. Right now I have the Socket and stream vars as private instance variables and a method for connecting to server which creates a new socket and then methods for opening and closing streams.
Just wondering how something like this could be typically handled. I've thought about having one humongous method which creates new socket, streams and handles all communication and closing of streams and socket, but it seems messy. Or maybe having a new thread create everything and then when the communication is over terminate the thread.
Ideas appreciated.
- Create a separate Thread at the Server end, when the Client connects to the Server.
- Do the process of read and writing onto the client socket for that particular client into that particular thread.
- And then terminate the Client thread when its done.
- If you again try to connect it, a new thread will span.
- You can always create a HashMap to keep tab on Client-Socket to Thread relation.
You should put all the "logic" in a new class, different than the GUI.
Then because you have 2 buttons, your Gui class should be able to call at least 2 methods on the logic class : connect() and disconnect(). Then in these methods you can handle all the work that is required to connect to a server, open/close streams etc...
That will make your code more clear, more maintainable, and maybe more evolutive if you plan to add features.
I would prefer create a thread for each socket creation and handle request and response withing that thread.
The call on ServerBootstrap.bind() returns a Channel but this is not in a Connected status and thus cannot be used for writing to client.
All the examples in Netty documentation show writing to a Channel from its ChannelHandler's events like channelConnected - I want to be able to get a connected Channel not in the event but as a reference outside the event , lets say some client code using my server component. One way is to manually code for waiting for channelConnected event and then copying the Channel reference.But this may be reinventing the wheel.
So the question is : Is there a blocking call available in Netty that returns a Connected Channel ?
edit : I am using Oio Channels , not Nio.
You could create a blocking call, but I think you maligned the event based approach too quickly. This is a contrived example, just to make sure I understand what you're trying to do:
Netty Server starts
A DataPusher service starts.
When a client connects, the DataPusher grabs a reference to the client channel and writes some data to it.
The client receives the pushed data shortly after connecting.
More or less correct ?
To do this, your DataPusher (or better yet, one of its minions) can be registered as a ChannelHandler in the server pipeline you create. Make it extend org.jboss.netty.channel.SimpleChannelHandler. The handler might look like this:
DataPusher dataPusher = getMyDataPusherReference();
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
dataPusher.doYourThing(e.getChannel()); // do something in another thread....
}
If you are determined to make it a blocking call from the DataPusher's perspective, just have it wait on a latch and have the minion drop the latch.
Not sure if that's what your'e looking for.....
After all the exchanges above, I still don't see that any of this is necessary.
Surely all you have to do is just accept the connection from the external service; don't register it for any events; then, when the other client connects, register for I/O events on both channels.
The external service doesn't know or care whether you are blocked in a thread waiting for another connection, or just not responding for some other reason.
If he's writing to you, his writes will succeed anyway, up to the size of your socket receive buffer, whether you are blocking or not, as long as you aren't actually reading from him. When that buffer fills up, he will block until you read some of it.
If he is reading from you, he will block until you send something, and again what you are doing in the meantime is invisible to him.
So I think you just need to simplify your thinking, and align it more with the wonderful world of non-blocking I/O.
I've got a program that opens N sockets to a server, each one in a different thread.
After sending two string for login porpuse, the program listen to the server, until an error occurs and the server sends the disconnect command, and the socket is closed. I want the program to reconnect once the server closes the socket : is it possible?
SocketList.add(new ConnectionHandler(id, actualSocket, out, in));
SocketRead p = new SocketRead(in, out, rowid);
new Thread(p).start();
I'd like that, when the socketread object receive the "DISCONNECT" command, the socket is restarts ( if needed, opening another thread).
I'm not sure what SocketList, ConnectionHandler or SocketRead are, so I'll assume they are classes that you've written for your application.
If you want to be able to reconnect, then you are going to have to change the structure of your code. On the one hand, the SocketRead object doesn't have the information needed to allow it to reconnect. On the other hand, the controlling code (your snippet) isn't able to detect the disconnect command.
It is not clear what will work best, but here are a couple of options:
pass the Socket (or the InetAddress and port number) to SocketRead and make it responsible for opening a new socket.
pass the Thread to the ConnectionHandler and make it responsible for detecting the death of the thread, creation of a new Socket and creating a new Thread.
pass the ConnectionHandler to the SocketRead object, hand have the latter call a callback or event handler method in the former when the socket disconnect occurs.
In the event handler of the DISCONNECT event, put in your reconnection logic.
For more information on how to write EventHandlers refer this link.