Back to project page android_asyncsocket.
The source code is released under:
GNU Lesser General Public License
If you think the Android project android_asyncsocket listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.smorra.asyncsocket; /*from w w w . j av a 2s .c o m*/ import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import android.app.Activity; import android.os.Handler; import android.os.Looper; public class TcpClient extends Thread implements DnsResolverCallback { TcpClientCallback tcc; DnsResolver dr; String host; int port; InetAddress ia; Pipe p; BigInteger bytesWritten = BigInteger.ZERO; BigInteger bytesQueued = BigInteger.ZERO; enum State { RESOLVING, CLOSED, CONNECTING, CONNECTED } State state = State.RESOLVING; public int bytesInQueue() { return bytesQueued.subtract(bytesWritten).intValue(); } public TcpClient(TcpClientCallback tcc, String host, int port) throws IOException { this.tcc = tcc; this.host = host; this.port = port; p = Pipe.open(); p.sink().configureBlocking(true); p.source().configureBlocking(false); dr = new DnsResolver(this, host); } public void write(byte[] b) throws IOException, InterruptedException { if (state != State.CONNECTED) throw new IOException("not connected"); p.sink().write(ByteBuffer.wrap(new byte[] { 0 })); ByteBuffer bb = ByteBuffer.allocate(4); bb.putInt(b.length); bb.rewind(); p.sink().write(bb); p.sink().write(ByteBuffer.wrap(b)); bytesQueued = bytesQueued.add(BigInteger.valueOf(b.length)); } public void close() throws IOException { if (state == State.CLOSED) throw new IOException("already closed"); if (state == State.RESOLVING) dr.cancel(); state = State.CLOSED; p.sink().write(ByteBuffer.wrap(new byte[] { 1 })); } @Override public void run() { try { SocketChannel sc = SocketChannel.open(); boolean connected = false; byte[] writeBuffer = new byte[0]; byte[] readBuffer = new byte[0]; sc.configureBlocking(false); sc.connect(new InetSocketAddress(ia, port)); while (true) { Selector selector = Selector.open(); if (!connected) { sc.register(selector, SelectionKey.OP_CONNECT); } else { sc.register(selector, SelectionKey.OP_READ); if (writeBuffer.length != 0) sc.register(selector, SelectionKey.OP_WRITE); } p.source().register(selector, SelectionKey.OP_READ); selector.select(); for (SelectionKey k : selector.selectedKeys()) { if (k.channel() == sc && k.isConnectable()) { try { if (sc.finishConnect()) { connected = true; new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (state == State.CLOSED) return; state = State.CONNECTED; tcc.onConnect(TcpClient.this); } }); } } catch (Exception e) { System.out.println("MOH"); e.printStackTrace(); sc.close(); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { state = State.CLOSED; tcc.onConnectFailed(TcpClient.this); } }); return; } } else if (k.channel() == sc && k.isReadable()) { ByteBuffer b = ByteBuffer.allocate(1024); int n = -1; try { n = sc.read(b); } catch (Exception e) { } if (n == -1) { sc.close(); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (state == State.CLOSED) return; tcc.onDisconnected(TcpClient.this); } }); return; } byte[] bytes = new byte[n]; System.arraycopy(b.array(), 0, bytes, 0, n); final byte[] readBytes = bytes; new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (state == State.CLOSED) return; tcc.onRead(TcpClient.this, readBytes); } }); } else if (k.channel() == sc && k.isWritable()) { //System.out.println("IS WRITABLE"); final int n; try { n = sc.write(ByteBuffer.wrap(writeBuffer)); } catch (Exception e) { sc.close(); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (state == State.CLOSED) return; tcc.onDisconnected(TcpClient.this); } }); return; } byte[] newWriteBuffer = new byte[writeBuffer.length - n]; System.arraycopy(writeBuffer, n, newWriteBuffer, 0, writeBuffer.length - n); writeBuffer = newWriteBuffer; if (writeBuffer.length == 0) { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { bytesWritten = bytesWritten.add(BigInteger.valueOf(n)); if (state == State.CONNECTED && bytesWritten.equals(bytesQueued)) { tcc.onWritten(TcpClient.this); } } }); } } else if (k.channel() == p.source() && k.isReadable()) { while (true) { ByteBuffer bb = ByteBuffer.allocate(1024); int n = p.source().read(bb); //System.out.println("Bytes read: " + n); byte[] readBuffer2 = new byte[readBuffer.length + n]; System.arraycopy(readBuffer, 0, readBuffer2, 0, readBuffer.length); System.arraycopy(bb.array(), 0, readBuffer2, readBuffer.length, n); readBuffer = readBuffer2; if (n != bb.capacity()) break; } while (true) { if (readBuffer.length >= 5 && readBuffer[0] == 0) { // write command byte[] length = new byte[] { readBuffer[1], readBuffer[2], readBuffer[3], readBuffer[4] }; int ilength = ByteBuffer.wrap(length).getInt(); if (readBuffer.length >= 5 + ilength) { byte[] wdata = new byte[ilength]; System.arraycopy(readBuffer, 5, wdata, 0, ilength); byte[] writeBufferNew = new byte[writeBuffer.length + wdata.length]; System.arraycopy(writeBuffer, 0, writeBufferNew, 0, writeBuffer.length); System.arraycopy(wdata, 0, writeBufferNew, writeBuffer.length, ilength); writeBuffer = writeBufferNew; byte[] readBufferNew = new byte[readBuffer.length - 5 - ilength]; System.arraycopy(readBuffer, 5 + ilength, readBufferNew, 0, readBuffer.length - 5 - ilength); readBuffer = readBufferNew; } else { break; } } else if (readBuffer.length >= 1 && readBuffer[0] == 1) { // close sc.close(); return; } else { // no more commands break; } } } } selector.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void onResolved(InetAddress[] ia) { this.ia = ia[0]; this.state = State.CONNECTING; start(); } @Override public void onResolveFailed() { state = State.CLOSED; System.out.println("DNS FAILED"); tcc.onConnectFailed(this); } }