Java Network: Improvised socket / InputStream
I'm implementing an event - oriented layer on a java socket. I wonder if there is a way to determine whether there is data to be read
My normal method is to read the buffer from the socket and call the callback provided when the buffer is filled with a fixed number of bytes (0 if the callback needs to be triggered every time it arrives), but I suspect that Java is already buffering me
Is the available () method of InputStream reliable? Should I read only () and do my own buffering on the socket? Or is there another way?
Solution
Soon, No Available () is unreliable (at least not for me) I recommend using Java. Net that connects to the selector and selectionkey nio. channels. socketChannel. This solution is somewhat event - based, but more complex than ordinary sockets
For customers:
>Construct a socket channel (socket) and open a selector (selector = selector. Open();). > Use non blocking socket configureBlocking(false); > Register selector socket for socket connection register(selector,SelectionKey.OP_CONNECT); > Connect socket Connect (New inetsocketaddress (host, port)); > See if there is a new selector select(); > If "new" indicates that the connection is successful, the selector OP is registered_ READ; If "new" refers to available data, just read it from the socket
However, in order to make it asynchronous, you need to set up a separate thread (although the socket is created as non blocking, the thread will still block), which will check whether something has been reached
For servers with serversocketchannel, you can use Op_ ACCEPT.
As a reference, this is my code (client). I should give you a hint:
private Thread readingThread = new ListeningThread(); /** * Listening thread - reads messages in a separate thread so the application does not get blocked. */ private class ListeningThread extends Thread { public void run() { running = true; try { while(!close) listen(); messenger.close(); } catch(ConnectException ce) { doNotifyConnectionFailed(ce); } catch(Exception e) { // e.printStackTrace(); messenger.close(); } running = false; } } /** * Connects to host and port. * @param host Host to connect to. * @param port Port of the host machine to connect to. */ public void connect(String host,int port) { try { SocketChannel socket = SocketChannel.open(); socket.configureBlocking(false); socket.register(this.selector,SelectionKey.OP_CONNECT); socket.connect(new InetSocketAddress(host,port)); } catch(IOException e) { this.doNotifyConnectionFailed(e); } } /** * Waits for an event to happen,processes it and then returns. * @throws IOException when something goes wrong. */ protected void listen() throws IOException { // see if there are any new things going on this.selector.select(); // process events Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); iter.remove(); // check validity if(key.isValid()) { // if connectable... if(key.isConnectable()) { // ...establish connection,make messenger,and notify everyone SocketChannel client = (SocketChannel)key.channel(); // Now this is tricky,registering for OP_READ earlier causes the selector not to wait for incoming bytes,which results in 100% cpu usage very,very fast if(client!=null && client.finishConnect()) { client.register(this.selector,SelectionKey.OP_READ); } } // if readable,tell messenger to read bytes else if(key.isReadable() && (SocketChannel)key.channel()==this.messenger.getSocket()) { // read message here } } } } /** * Starts the client. */ public void start() { // start a reading thread if(!this.running) { this.readingThread = new ListeningThread(); this.readingThread.start(); } } /** * Tells the client to close at nearest possible moment. */ public void close() { this.close = true; }
For servers:
/** * Constructs a server. * @param port Port to listen to. * @param protocol Protocol of messages. * @throws IOException when something goes wrong. */ public ChannelMessageServer(int port) throws IOException { this.server = ServerSocketChannel.open(); this.server.configureBlocking(false); this.server.socket().bind(new InetSocketAddress(port)); this.server.register(this.selector,SelectionKey.OP_ACCEPT); } /** * Waits for event,then exits. * @throws IOException when something goes wrong. */ protected void listen() throws IOException { // see if there are any new things going on this.selector.select(); // process events Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); // do something with the connected socket iter.remove(); if(key.isValid()) this.process(key); } } /** * Processes a selection key. * @param key SelectionKey. * @throws IOException when something is wrong. */ protected void process(SelectionKey key) throws IOException { // if incoming connection if(key.isAcceptable()) { // get client SocketChannel client = (((ServerSocketChannel)key.channel()).accept()); try { client.configureBlocking(false); client.register(this.selector,SelectionKey.OP_READ); } catch(Exception e) { // catch } } // if readable,tell messenger to read else if(key.isReadable()) { // read } }
I hope this will help