Thx and verified both Time* and Chat* examples work now. I study and experiment more with the wrapper classes.
ps: I think “protected NioReadStrategy defaultStrategy = NioReadStrategy.READ_CALLBACK;” field is obsolete now in NioClient class.
Thx and verified both Time* and Chat* examples work now. I study and experiment more with the wrapper classes.
ps: I think “protected NioReadStrategy defaultStrategy = NioReadStrategy.READ_CALLBACK;” field is obsolete now in NioClient class.
Ah, right.
Simplified the dirty internals. Improved performance a LOT. :persecutioncomplex:
Network data is copied 1 time now when using the HANDLER
strategy.
Network data is copied 2 times when using the CALLBACK
strategy, due to the ByteBuffer->byte[]
conversion.
It used to depend on the (mis)match between incoming fragments and ReadCallback
size…
Everything is handled internally using ByteBuffer
s, created by a {Direct|Heap}ByteBufferFactory
.
The copies are efficient, not the occasional byte-by-byte loops anymore: when using direct ByteBuffers
you get superior performance.
Excuse me for rambling…!
So I totally revamped the API. It’s a lot more gentle on the user now.
You don’t have to squeeze eventhing into one NioNetworkHandler
You can simply call network.addHandler(NioNetworkHandler)
and it will receive events.
You can now also, for ultimate performance, mess with the ‘transfer buffer’, for zero copy transfers, further, there is a NioClient.flushOrDie()
method added, so that you can attempt a non-blocking flush, which will throw an exception if it fails.
The classes are now nicely spread over 2 packages, and the dependency on my custom Logger is now gone.
I don’t think i’ve ever seen someone so excited over NIO ;D
Good job though, i’m sure many people will find your code useful and pass it off as their own
Not really excited, just desperate for attention, eh! :persecutioncomplex:
I just hope my user base will increase from 0 to 1, that’d make my day.
Besides that, it really shows how incredibly horrific NIO is. My wrapper is (becoming) quite chunky, yet it basically does nothing else than what you (you, Abuse!) would code up in a few minutes in java.io.* + java.net.*
And then, Linux threads are getting so darn efficient that with enough memory (!) they seriously outperform fine-tuned Selectors, with a one-thread-per-connection model. NIO is only really useful on memory limited systems these days (that means indies, yay!).
I should make a project page for this on some fancy opensource rep.
If anybody has doubts about the implementation: I’m currently running/stresstesting a very rough HTTP server on top of this API, doing 2500 concurrent connections, with ~1100 HTTP requests/sec.
:-X
yup sounds like a good idea, also do remember to give the library a nice snappy name too.
You mean, like… Johny ?
Pff. I suck at names.
Well when i first saw this thread, i read the title as ‘Covenant’ (as in the baddies in Halo :)) and thought that was the name of the library. So that might be one name you could choose.
nioda (nyo-da) - native i/o damage amplifier… haha ;D
It’s totally aimed at the TCP part of NIO. I mean, UDP is already nearly single-threaded.
So the name shouldn’t have NIO in it.
I was thinking of ‘Iowa’ (IO Wrapper API) ? But how to find it… it will be completely swamped.
Hmmmm I just wrote some code myself to do exactly this!!
Annoying to have spotted this a few days too late… ah well
If anyone is interested, my code is here:
http://code.google.com/p/mikeralib/source/browse/#svn/trunk/Mikera/src/mikera/net
Nice API, but there are some problems.
When you read from the channel, and you get an IOException, (as opposed to a -1 return value), you will end up with a socket channel that will remain open.
You also create a new selector + a new thread for every connect (not accept). Also, keep in mind that interfacing with the native network buffers is really expensive. You have tied your networking API to a 4byte+payload protocol, but you also read your data that way. It’s going to slow you down if you first try to read 4 bytes, and then the payload, especially when you have 20 packets in your inbound buffer, and you have to call channel.read 40 times. Better to just read everything available and slice and dice it in your own code. You also don’t seem to support asynchronous connect (OP_CONNECT) which is not really bad…
Overall, nice API, but unfortunately ties the user to a 4B+data protocol, which means you never can implement oldschool stuff like HTTP, FTP, POP3, SMTP, etc, etc, on top of it, but then again, your probably only going to use it in your own program.
Cool, thanks for the feedback - I’ll have a go at fixing these points since this is just my first attempt at hacking together a networking protocol!
My main design criteria was having a simple, asynchronous API with relatively low overhead for my own applications. The point of the 4 byte message length protocol is that the networking library needs to know when the end of the message is, so that it only invokes the message handler once it has received a complete message. This simplifies the receiving code significantly since you don’t have to test and wait for a complete message etc.
I’m considering an smarter encoding where the message length is 1 byte for short messages (up to 127 bytes), 2 bytes for slightly longer ones, 3 bytes once it hits 16k etc.
I know what the 4B protocol is for, I’m just saying that you don’t necessarily have to hardcode that in a I/O library. I added on top of the lib, as tiny classes: Packet and PacketListener. The core classes just pump the received data into a bytebuffer, and from there into the packets, much faster than querying the OS for the next few bytes.
What’s the license on this, riven?
Hi Notch, special offer for you: BSD.
I love you =D
Just to satisfy my personal curiosity: what are you going to use it for?