Improving Java Network ProgrammingTopicsEnterprise Application InfrastructureJava Toolkit TeamA Simple Distributed ApplicationDefinitionsjava.netSlide 8Slide 9java.nioSlide 11Slide 12Event Based Network ProgrammingEvent Based ClientSlide 15Event Based ServerSlide 17IssuesLong Running CallbacksMessage FramingResilienceSlide 22Questions?Thank you.Improving Java Network ProgrammingBrian Runk, [email protected] Apr 2006Topics -Background-A simple distributed application-java.net programming model-java.nio programming model-A better programming model-Issues-Q & AEnterprise Application Infrastructure-Global team providing software infrastructure and developer toolsC++, Java, .Net, Perl, PythonLinux, Solaris, Windows-True software reuseSingle place for feature requirements and bug fixesWell known repositories for documentation and best practicesAll application developers can leverage expertise-Support for Firmwide initiatives-Changes to infrastructure affects many applicationsJava Toolkit Team-15 people globally-40+ proprietary and open source libraries-Developer tools, build infrastructure-Documentation, best practices, guidelines-Hundreds of Java developers-Thousands of Java applicationsA Simple Distributed Application ClientServerDefinitions-Connection: a two way communication channel between two processes-Socket: one end of a connection-Client: connection initiator-Server: connection acceptor-Message: a meaningful and complete set of bytesjava.net-Blocking socketsyou wait until work is done, maybe forever-no timeout for synchronous operations-Simple stream based APISocket s = new Socket(“foo.ms.com”, 12345);write these bytesbyte[] data = ...;s.getOutputStream().write(data);I’m expecting data, read as much as you can into this byte buffer, tell me how many bytes you gotbyte[] data = new byte[1024];int numRead = s.getInputStream().read(buf);java.net-Servers must have at least one thread per clientServerSocket svr = new ServerSocket(12345);while (Socket s = svr.accept()){ new SocketProcessorThread(s).start();}java.netclass SocketProcessorThread extends Thread { SocketProcessorThread(Socket s) { ... } public void run() { do { Request req = readRequest(s.getInputStream()); Response res = calculateResponse(req); s.getOutputStream.write(res); } while (the client hasn't disconnected or otherwise indicated that it's done) }}-Doesn’t scale to thousands of clientsjava.nio-Non-blocking socketswill only do as much as they can without blockingreport back to you how much was done-Complex Selector based APISocketChannel sc = SocketChannel.open();InetSocketAddress addr = ...;if (!sc.connect(addr)){ Selector selector = Selector.open(); sc.register(select, SelectionKey.OP_CONNECT); if (selector.select() > 0) { //blocks until ready if (!sc.finishConnect()) { // not connected } }}java.nioServerSocketChannel server = ServerSocketChannel.open();server.configureBlocking(false);server.socket().bind(new InetSocketAddress(port)); Selector selector = Selector.open();server.register(selector, SelectionKey.OP_ACCEPT);java.niowhile (true) {if (selector.select() > 0) { for (SelectionKey key: selector.selectedKeys()) { if (key.isAcceptable()){ // accept client SocketChannel // register it with the selector for READ } else if (key.isReadable()) { // do something with data read from SocketChannel // unless there was none, meaning the client disconnected // if you want to send a response, hang on to it // and register with selector for WRITE } else if (key.isWritable()) { // get the message you held on to for this client // send as much as you can. if done, unregister // with selector for WRITE } }}Event Based Network Programming- Callback API for network eventsgot connectedgot disconnecteddata arrivedsent data completednew client connection client connection disconnected-Single thread for I/OEvent Based ClientIOThread loop = new IOThread();loop.start();Client c = new Client(loop, new HostPort(“foo.ms.com:12345”), “FooClient”);c.addListener(new ClientListener());c.startConnect(); // asynchronousEvent Based Clientpublic class ClientListener implements ClientCallbacks { public void connectCallback() { // connection is established, send login data // or first message } public void disconnectCallback() { // the server disconnected. what can we do // other than log an error? } public void readCallback(byte[] data) { // data arrived, can do something now. // but what if it’s not a whole message? // what if it’s three messages? } public void sendDone() { // in case you’re wondering }}Event Based ServerIOThread loop = new IOThread();loop.start();Server s = new Server(loop, 12345, “FooServer”);c.addListener(new ServerListener());c.startAccepting();Event Based Serverpublic class ServerListener implements ServerCallbacks { public void clientConnectCallback(Client c) { // a new client has connected // initialize any client context } public void clientDisconnectCallback(Client c) { // the client disconnected. cleanup } public void readCallback(Client c, byte[] data) { // client sent some data, can do something now. // but what if it’s not a whole message? // what if it’s three messages? }}Issues-Long running callbacksI/O thread is shared. long running callbacks slow down other clients-Message framingWhat if the bytes I get aren’t quite the bytes I want?-ResilienceWhat if I didn’t want to get disconnected?Long Running Callbacks-Keep callbacks shortrequires developer compliancenot always possible-Distribute connections in a pool of I/O threadssame problem exists but at potentially smaller scale-Only use I/O threads for I/Ouse a thread pool for application workMessage Framing-Message definition frameworkpublic interface MessageDefinition {byte[] makeMessage(byte[] readBuffer);}-Framework buffers read bytesUses application provided MessageDefinition implementation to make messagesOnly invokes readCallback with complete messages.Resilience-If connect fails, keep trying.solves startup ordering problemexponential backoff-If you get disconnected, try to reconnectsame as connectlist of primary and backup servers-try primary servers firststart
View Full Document