Multiplexing a client connection
Frederic Bregier
fredbregier at free.fr
Thu Jul 30 02:32:05 EDT 2009
Hi Jon,
On the channel itself, the isSucess only said that the channel was opened successfully. If you want to check if the channel is still opened, you have to use the isConnected() method which tests if the channel is still opened.
It should work better for that part.
For the write themselves, this should be the more difficult part, due to asynchrous and multi threading. Here are some points I think about that could bring problems:
- as close and open channe operationsl are asynchronous, while those operations are running, other threads can try to write/close/open to/a channel, which can lead to deadlock (in fact not deadlock but not correct behaviour)
- multi threading in such approach of sharing channel must take care of such "thread safe" approach, since when a close or open function is on going, you have to be sure this thread is really the only one that is currently doing so on this channel. If not, you can have something like one thread try to write, see this is closed, try to reopen it, while another thread is doing excatly the same stuff, thus having two new channels for the same context, which is wrong for you...
On the solution, several things can be done. I'm not pretending I know all. But at least here are some of my ideas. See if those can help you...
- For the ClosedChannelExecption, you can trap it such that you re-send the message to the new channel from here. But if you use listener on write operation, you don't need to rewrite here, just close the channel.
- To take care of the multiple threads trying to write to the same channel, I would suggest two kinds of approach.
The first one is the one that I previously suggested: each thread test the channel (isConnected) and try to write adding a listener on the write operation to retry the write if any problem occurs. The real problem is not this part but to answer to this question: who is responsible to reopen a channel when it is closed?
For this, either this is the threads that tries to write, or this is another part (the channel itself in fact), which could lead to simplicity.
So the second approach, which in fact will continue to use the first one, is just to move the responsability to the channel itself and not to the threads writers.
To do so, what I could do is to implement a special data structure (the one where you put the ClientBootStrap and the current Channel) that is handled by the current channel itself.
- channelConnected: the channel registers itself to this data structure (if this is the only one such channel, it is simple. If there could be more than one such channel - group of multiple threads writing to one sub channel - then you have to have a key to find it in a hashmap. But if I recall correctly, your program does only have one such channel, so it should be easy).
- channelClosed: the channel registers itself as close and starts a new channel immediately, letting this new channel registering itself
- exceptionCaught: filter if necessary the exceptions, but close the channel if an error occurs (thus leading to unregister and creation of a new one)
On writer side (thread writers), each write should call a special method on this object that will block until the channel is ready (registered). For instance something like: isReady() that
- first test if there is a registered channel
- if so, is this registered channel connected (isConnected)
- then write but adding a listener that will try again on the global object (in order to have the new registered channel)
- if any problem occurs (no registered channel, not connected), just wait using a future (your own one probably) on newly registered channel before continue. On write, this will be done by the listener itself
By the way, ClosedChannelException is normal since you will have certainly write in process while the channel is closing. As you add a listerner on every write operation, it should restart from scratch with the new registered channel. So that you can safely ignored this exception for you (if it works of course ;-)
So to resume, I think the most difficult part is to defined who is responsible to close/open a channel, and I think this should be the channel itself... At least, once you open it a first time before any action ;-)
Then, on writer part, you have to put some future to enable those threads to wait gracefuly for the new channel to be connected and to wake up easily. I think you shouldn't make an active wait (like a loop with Thread.sleep), but it can do the trick also, but it is less "beautiful"... When I write "the channel registered itself (or unregistered)", what I mean was those kind of future (let say one for isActive successful after connection so that each thread if the channel is not opened will wait on this future to be sucessful).
Quite challenging idea... ;-)
Thanks to make me think about such ideas!!
HTH,
Frederic
----- Original Message -----
From: JonY (via Nabble)
To: Frederic Bregier
Sent: Thursday, July 30, 2009 5:23 AM
Subject: Re: Multiplexing a client connection
Frederic,
Thank you for your reply.
Unfortunately, I've had some trouble implementing your solution. I created an object to contain the client bootstrap and channel and I pass it to my client and server handlers. I put a listener on all messages that attempt to send on the channel. The listener checks the isSuccess() function and, if false, tries to connect on the bootstrap again.
I have a channelfuture for this conection which returns true to isSuccess(), but when I try to write to this new channel, it throws a ClosedChannelException just like before.
Does isSuccess() tell you whether or not the connection actually worked, or is it a purely user-set flag? I haven't been able to find a definitive answer to this in the documentation. Regardless, I feel like this approach should work. Do you have any ideas as to why it isn't?
Thank you for your help,
Jon
Frederic Bregier wrote:
Hi Jony,
As far as I understand your questions, you have to face up several differents problems.
A client bootstrap is somehow a shortcut to enable easier connection. So if you use it to reconnect when the previous channel is over (closed), it is just fine.
Now, to keep the reference of your "current" client channel (as it could change), I would suggest you to store it in an object that would contain for instance the bootstrap but also the last and current active channel. Doing that, you will have to pass this object to each server channel, such that you can write to the current and active client channel.
Now to replay the messages that weren't sent through the local client channel, several ways (and other that I don't have in mind right now) can be achieved (less simple):
- you can first test if the channel is still connected before writing. If so just write, if not, re open the channel, replacing the previous one with the new one. Take care to be "thread safe" there since it could be a minn breaker (take care that if a problem occurs, only one thread will try to reopen the channel and that other will wait this operation is ok to reuse the result and to not close and reopen again a new one when not necessary). This would be the most difficult operation.
- Perhaps a more simpler way would be to only add this handling in exceptionCaught and channelClosed of the client channel such that it only occurs there. However, for write operation, you should add something to test the channel is still connected or in reconnection process...
- you can also be blocking on the write operation (await), but keep attention that you will have blocking operation, thus less efficiency. If the operation is not in success, you know that you will have to send again it through the new client channel.
- you can also add a listener on each write operation (much better than await), a future listener on close or error, such that you will be informed asynchronously that there was a problem, such that you can send again your message. Note that the future listener will only inform you of the end of the operation (and therefore the status) but you will have to create a new future listener for each write such that in the constructor of this future listener you can pass the message you wanted to write again in case of error. Doing this way, I would suppose that you don't need to have a list of messages since the future listeners will do that for you.
Well, I could say more, but I think this is a start, some ideas...
HTH,
Frederic
JonY wrote:
Hello Everyone,
I'm pretty new to netty, and I'm having a little trouble implementing a solution that I believe netty can handle. What I have so far is an application that contains a client bootstrap and a server bootstrap. The server accepts multiple connections and writes them to the client bootstrap's one persistent channel. The way I've done this is by passing the client bootstrap's channel to the server's handler and writing to it (I'm assuming there's a better/safer way to do this?).
In addition to improving my current implementation, I need to be able to reconnect the client piece if the connection dies (i.e. unplugging the cable). I've tried reconnecting the channel in the client handler, but the channel sometimes gets closed even if the connection dies. I've also tried a number of other solutions involving trying to reconnect the bootstrap, etc from the exceptionCaught handler.
Given my current implementation, I need some way to reconnect the client bootstrap and then send the new channel to the server bootstrap. The server bootstrap then needs to start writing all of the data that has been queuing on the old channel to the new channel.
Any help/suggestions would be greatly appreciated!
Jon
------------------------------------------------------------------------------
View message @ http://n2.nabble.com/Multiplexing-a-client-connection-tp3347008p3354060.html
To unsubscribe from Re: Multiplexing a client connection, click here.
-----
Hardware/Software Architect
--
View this message in context: http://n2.nabble.com/Multiplexing-a-client-connection-tp3347008p3354532.html
Sent from the Netty User Group mailing list archive at Nabble.com.
More information about the netty-users
mailing list