当前位置:   article > 正文

Android与Java AIO实现简单Echo服务器与客户端_android aio

android aio

写完了NIO就来了AIO(NIO 2.0)吧~

Android需要sdk version  26及以上才支持了AIO。

AIO的优势是异步,全部的收发消息都是通过回调的方式来实现。


Server端,纯Java代码:

  1. public class EchoServer {
  2. public static final int MAX_SIZE = 256; // max size 256
  3. public static Charset mCharSet = Charset.forName("UTF-8"); //encode and decode charset
  4. public static void main(String args[]) {
  5. AsyncServerThread serverHandler = new AsyncServerThread(8999);
  6. new Thread(serverHandler).start();
  7. }
  8. }

  1. public class AsyncServerThread implements Runnable {
  2. private AsynchronousServerSocketChannel mServerChannel;
  3. private static CountDownLatch serverStatus = new CountDownLatch(1);
  4. public AsyncServerThread(int port) {
  5. try {
  6. mServerChannel = AsynchronousServerSocketChannel.open();
  7. mServerChannel.bind(new InetSocketAddress(port));
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. @Override
  13. public void run() {
  14. mServerChannel.accept(this, new AcceptHandler());
  15. try {
  16. // 在闭锁到达结束状态之前,这扇门一直是关闭着的,不允许任何线程通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。且当门打开了,就永远保持打开状态。
  17. serverStatus.await();
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. public AsynchronousServerSocketChannel getServerChannel() {
  23. return mServerChannel;
  24. }
  25. }

AcceptHandler负责处理客户端连接

  1. public class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, AsyncServerThread> {
  2. @Override
  3. public void completed(AsynchronousSocketChannel asynchronousSocketChannel, AsyncServerThread asyncServerThread) {
  4. AsynchronousServerSocketChannel serverChannel = asyncServerThread.getServerChannel();
  5. serverChannel.accept(asyncServerThread, this);
  6. try {
  7. System.out.println("connected from: " + asynchronousSocketChannel.getRemoteAddress());
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. }
  11. //创建新的Buffer
  12. ByteBuffer buffer = ByteBuffer.allocate(EchoServer.MAX_SIZE);
  13. //异步读 第三个参数为接收消息回调的业务Handler
  14. asynchronousSocketChannel.read(buffer, buffer, new ReadHandler(asynchronousSocketChannel));
  15. }
  16. @Override
  17. public void failed(Throwable throwable, AsyncServerThread asyncServerThread) {
  18. }
  19. }

ReadHandler负责处理收到的消息。

  1. public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
  2. private AsynchronousSocketChannel mChannel;
  3. public ReadHandler(AsynchronousSocketChannel channel) {
  4. this.mChannel = channel;
  5. }
  6. @Override
  7. public void completed(Integer integer, ByteBuffer byteBuffer) {
  8. //flip操作
  9. byteBuffer.flip();
  10. //根据
  11. byte[] message = new byte[byteBuffer.remaining()];
  12. byteBuffer.get(message);
  13. String data = new String(message, EchoServer.mCharSet);
  14. System.out.println("received: " + data);
  15. String response = "response:" + data;
  16. //向客户端发送消息
  17. doWrite(response);
  18. }
  19. @Override
  20. public void failed(Throwable throwable, ByteBuffer byteBuffer) {
  21. }
  22. //发送消息
  23. private void doWrite(String result) {
  24. System.out.println("send back: " + result);
  25. byte[] bytes = result.getBytes();
  26. ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
  27. writeBuffer.put(bytes);
  28. writeBuffer.flip();
  29. //异步写数据 参数与前面的read一样
  30. mChannel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
  31. @Override
  32. public void completed(Integer result, ByteBuffer buffer) {
  33. //如果没有发送完,就继续发送直到完成
  34. if (buffer.hasRemaining()) {
  35. mChannel.write(buffer, buffer, this);
  36. } else {
  37. //创建新的Buffer
  38. ByteBuffer readBuffer = ByteBuffer.allocate(1024);
  39. //异步读 第三个参数为接收消息回调的业务Handler
  40. mChannel.read(readBuffer, readBuffer, new ReadHandler(mChannel));
  41. }
  42. }
  43. @Override
  44. public void failed(Throwable exc, ByteBuffer attachment) {
  45. try {
  46. mChannel.close();
  47. } catch (IOException e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. });
  52. }
  53. }

到这里服务端就完成了。代码会比Java NIO看起来更好理解一些。都是基于回调的方式来处理。


Client,Android来实现:

  1. public class MainActivity extends AppCompatActivity {
  2. private static final String TAG = MainActivity.class.getSimpleName();
  3. public static final int MAX_SIZE = 256; // max size 256
  4. public static Charset mCharSet = Charset.forName("UTF-8"); //encode and decode charset
  5. private EditText mIpEt;
  6. private EditText mPortEt;
  7. private Button mConnBtn;
  8. private TextView mScreenTv;
  9. private EditText mInputEt;
  10. private Button mSendBtn;
  11. private SocketThread mSocketThread;
  12. private static Handler mMainHandler;
  13. public static final int MSG_CONNECT = 0x001;
  14. public static final int MSG_RECEIVE = 0x002;
  15. public static final int MSG_SEND_ERROR = 0x003;
  16. public static final String DATA_RECEIVE = "data_receive";
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. mIpEt = findViewById(R.id.main_ip_et);
  22. mPortEt = findViewById(R.id.main_port_et);
  23. mConnBtn = findViewById(R.id.main_connect_btn);
  24. mScreenTv = findViewById(R.id.main_screen_tv);
  25. mInputEt = findViewById(R.id.main_input_et);
  26. mSendBtn = findViewById(R.id.main_send_btn);
  27. // defalut value. Change it to your own server ip
  28. mIpEt.setText("172.16.62.65");
  29. mPortEt.setText("8999");
  30. mConnBtn.setOnClickListener(new View.OnClickListener() {
  31. @Override
  32. public void onClick(View v) {
  33. String ip = mIpEt.getText().toString();
  34. String port = mPortEt.getText().toString();
  35. if (TextUtils.isEmpty(ip) || TextUtils.isEmpty(port)) {
  36. Toast.makeText(MainActivity.this, "ip or port is null", Toast.LENGTH_SHORT).show();
  37. } else {
  38. connectToServer(ip, Integer.valueOf(port));
  39. }
  40. }
  41. });
  42. mSendBtn.setOnClickListener(new View.OnClickListener() {
  43. @Override
  44. public void onClick(View v) {
  45. String data = mInputEt.getText().toString();
  46. if (!TextUtils.isEmpty(data)) {
  47. mSocketThread.sendMsgToServer(data);
  48. }
  49. }
  50. });
  51. // TODO handler may cause memory leaks
  52. mMainHandler = new Handler() {
  53. @Override
  54. public void handleMessage(Message msg) {
  55. switch (msg.what) {
  56. case MSG_CONNECT:
  57. Toast.makeText(MainActivity.this, "Connect to Server Success", Toast.LENGTH_SHORT).show();
  58. mConnBtn.setText("Connected");
  59. mConnBtn.setEnabled(false);
  60. break;
  61. case MSG_RECEIVE:
  62. Bundle data = msg.getData();
  63. String dataStr = data.getString(DATA_RECEIVE);
  64. Log.i(TAG, "received data:" + dataStr);
  65. CharSequence originData = mScreenTv.getText();
  66. String result = originData + "\n" + dataStr;
  67. mScreenTv.setText(result);
  68. break;
  69. case MSG_SEND_ERROR:
  70. Toast.makeText(MainActivity.this, "Send Error, Connection may be Closed", Toast.LENGTH_SHORT).show();
  71. break;
  72. }
  73. }
  74. };
  75. }
  76. private void connectToServer(String ip, int port) {
  77. mSocketThread = new SocketThread(ip, port);
  78. mSocketThread.start();
  79. }
  80. private static class SocketThread extends Thread {
  81. private String mIp;
  82. private int mPort;
  83. private AsynchronousSocketChannel mClientChannel;
  84. private CountDownLatch mLatch;
  85. public SocketThread(String ip, int port) {
  86. this.mIp = ip;
  87. this.mPort = port;
  88. try {
  89. mClientChannel = AsynchronousSocketChannel.open();
  90. } catch (IOException e) {
  91. e.printStackTrace();
  92. }
  93. }
  94. @Override
  95. public void run() {
  96. mLatch = new CountDownLatch(1);
  97. AsyncClientHandler asyncClientHandler = new AsyncClientHandler(mClientChannel, mMainHandler);
  98. mClientChannel.connect(new InetSocketAddress(mIp, mPort), asyncClientHandler, asyncClientHandler);
  99. try {
  100. mLatch.await();
  101. } catch (InterruptedException e1) {
  102. e1.printStackTrace();
  103. }
  104. try {
  105. mClientChannel.close();
  106. } catch (IOException e) {
  107. e.printStackTrace();
  108. }
  109. }
  110. public void sendMsgToServer(final String data) {
  111. new Thread(new Runnable() {
  112. @Override
  113. public void run() {
  114. byte[] bytes = data.getBytes(mCharSet);
  115. ByteBuffer dataBuffer = ByteBuffer.allocate(bytes.length);
  116. dataBuffer.put(bytes);
  117. dataBuffer.flip();
  118. Log.i(TAG, "send data" + data);
  119. //输出到通道
  120. mClientChannel.write(dataBuffer, dataBuffer, new CompletionHandler<Integer, ByteBuffer>() {
  121. @Override
  122. public void completed(Integer result, ByteBuffer buffer) {
  123. //如果没有发送完,就继续发送直到完成
  124. if (buffer.hasRemaining()) {
  125. mClientChannel.write(buffer, buffer, this);
  126. }
  127. }
  128. @Override
  129. public void failed(Throwable exc, ByteBuffer attachment) {
  130. try {
  131. mMainHandler.sendEmptyMessage(MSG_SEND_ERROR);
  132. mClientChannel.close();
  133. } catch (IOException e) {
  134. e.printStackTrace();
  135. }
  136. }
  137. });
  138. }
  139. }).start();
  140. }
  141. }
  142. }

布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical"
  6. android:layout_margin="15dp">
  7. <EditText
  8. android:id="@+id/main_ip_et"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:hint="ip address"/>
  12. <EditText
  13. android:id="@+id/main_port_et"
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content"
  16. android:hint="port"
  17. android:inputType="number"/>
  18. <Button
  19. android:id="@+id/main_connect_btn"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"
  22. android:layout_gravity="center"
  23. android:text="Connect"/>
  24. <EditText
  25. android:id="@+id/main_input_et"
  26. android:layout_width="match_parent"
  27. android:layout_height="wrap_content"
  28. android:hint="message to server"/>
  29. <Button
  30. android:id="@+id/main_send_btn"
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:layout_gravity="center"
  34. android:text="Send"/>
  35. <ScrollView
  36. android:layout_width="match_parent"
  37. android:layout_height="match_parent"
  38. android:layout_marginTop="10dp">
  39. <TextView
  40. android:id="@+id/main_screen_tv"
  41. android:layout_width="match_parent"
  42. android:layout_height="wrap_content"
  43. android:text="received message will be shown here"/>
  44. </ScrollView>
  45. </LinearLayout>

客户端的连接处理:

  1. public class AsyncClientHandler implements CompletionHandler<Void, AsyncClientHandler> {
  2. private static final String TAG = AsyncClientHandler.class.getSimpleName();
  3. private AsynchronousSocketChannel mClientChannel;
  4. private Handler mMainHandler;
  5. public AsyncClientHandler(AsynchronousSocketChannel clientChannel, Handler mainHandler) {
  6. mClientChannel = clientChannel;
  7. mMainHandler = mainHandler;
  8. }
  9. @Override
  10. public void completed(Void result, AsyncClientHandler attachment) {
  11. Log.i(TAG, "connect to server success!");
  12. mMainHandler.sendEmptyMessage(MainActivity.MSG_CONNECT);
  13. ByteBuffer buffer = ByteBuffer.allocate(MainActivity.MAX_SIZE);
  14. mClientChannel.read(buffer, buffer, new ReadHandler(mClientChannel, mMainHandler));
  15. }
  16. @Override
  17. public void failed(Throwable exc, AsyncClientHandler attachment) {
  18. Log.i(TAG, "connect to server failed!");
  19. exc.printStackTrace();
  20. try {
  21. mClientChannel.close();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

收消息处理:

  1. public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
  2. private static final String TAG = "ReadHandler";
  3. private AsynchronousSocketChannel mClientChannel;
  4. private Handler mMainHandler;
  5. public ReadHandler(AsynchronousSocketChannel clientChannel, Handler mainHandler) {
  6. mMainHandler = mainHandler;
  7. mClientChannel = clientChannel;
  8. }
  9. @Override
  10. public void completed(Integer integer, ByteBuffer byteBuffer) {
  11. //flip操作
  12. byteBuffer.flip();
  13. //根据
  14. byte[] data = new byte[byteBuffer.remaining()];
  15. byteBuffer.get(data);
  16. String dataStr = new String(data, MainActivity.mCharSet);
  17. Log.i(TAG, "received: " + dataStr);
  18. Message message = mMainHandler.obtainMessage();
  19. message.what = MainActivity.MSG_RECEIVE;
  20. Bundle bundle = new Bundle();
  21. bundle.putString(MainActivity.DATA_RECEIVE, dataStr);
  22. message.setData(bundle);
  23. mMainHandler.sendMessage(message);
  24. ByteBuffer buffer = ByteBuffer.allocate(MainActivity.MAX_SIZE);
  25. mClientChannel.read(buffer, buffer, new ReadHandler(mClientChannel, mMainHandler));
  26. }
  27. @Override
  28. public void failed(Throwable throwable, ByteBuffer byteBuffer) {
  29. }
  30. }

大功告成。

试验一下~


Server端打印的日志





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/160713
推荐阅读
相关标签
  

闽ICP备14008679号