创建阻塞的 EchoClient

客户程序一般不需要同时建立与服务器的多个连接,因此用一个线程,按照阻塞模式运行就能满足需求

  1. public class EchoClient {
  2. private SocketChannel socketChannel = null;
  3. public EchoClient() throws IOException {
  4. socketChannel = SocketChannel.open();
  5. InetAddress ia = InetAddress,getLocalHost();
  6. InetSocketAddress isa = new InetSocketAddress(ia,8000);
  7. socketChannel.connect(isa); //连接服务器
  8. }
  9. public static void main(String args[])throws IOException {
  10. new EchoClient().talk();
  11. }
  12. private PrintWriter getWriter(Socket socket) throws IOException {
  13. OutputStream socketOut = socket.getOutputStream();
  14. return new PrintWriter(socketOut,true);
  15. }
  16. private BufferedReader getReader(Socket socket) throws IOException {
  17. InputStream socketIn = socket.getInputStream();
  18. return new BufferedReader(new InputStreamReader(socketIn));
  19. }
  20. public void talk() throws IOException {
  21. try {
  22. BufferedReader br = getReader(socketChannel.socket());
  23. PrintWriter pw = getWriter(socketChannel.socket());
  24. BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
  25. String msq = null;
  26. while((msg = localReader.readLine()) != null) {
  27. pw.println(msg);
  28. System.out.println(br.readLine());
  29. if(msq.equals("bye")) {
  30. break;
  31. }
  32. }
  33. } catch(IOException e) {
  34. e.printStackTrace();
  35. } finally {
  36. try {
  37. socketChannel.close();
  38. } catch(IOException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. }
  43. }

创建非阻塞的 EchoClient

对于客户与服务器之间的通信,按照它们收发数据的协调程度来区分,可分为同步通信和异步通信

同步通信指甲方向乙方发送了一批数据后,必须等接收到了乙方的响应数据后,再发送下一批数据。同步通信要求一个 IO 操作完成之后,才能完成下一个 IO 操作,用阻塞模式更容易实现

异步通信指发送数据和接收数据的操作互不干扰,各自独立进行。异步通信允许发送数据和接收数据的操作各自独立进行,用非阻塞模式更容易实现

值得注意的是,通信的两端并不要求都采用同样的通信方式,当一方采用同步通信时,另一方可以采用异步通信

  1. public class EchoClient {
  2. private SocketChannel socketChannel = null;
  3. private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
  4. private ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
  5. private Charset charset = Charset.forName("GBK");
  6. private Selector selector;
  7. public EchoClient() throws IOException {
  8. socketChannel = SocketChannel.open();
  9. InetAddress ia = InetAddress.getLocalHost();
  10. InetSocketAddress isa = new InetSocketAddress(ia, 8000);
  11. socketChannel.connect(isa); //采用阻塞模式连接服务器
  12. socketChannel.configureBlocking(false); //设置为非阻塞模式
  13. selector = Selector.open();
  14. }
  15. public static void main(String args[]) throws IOException {
  16. final EchoClient client = new EchoClient();
  17. Thread receiver=new Thread() {
  18. public void run() {
  19. client.receiveFromUser(); //接收用户向控制台输入的数据
  20. }
  21. };
  22. receiver.start();
  23. client.talk();
  24. }
  25. /** 接收用户从控制台输入的数据,放到sendBuffer中 */
  26. public void receiveFromUser() {
  27. try {
  28. BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
  29. String msg = null;
  30. while((msg = localReader.readLine()) != null) {
  31. synchronized(sendBuffer) {
  32. sendBuffer.put(encode(msg + "\r\n"));
  33. }
  34. if (msg.equals("bye")) {
  35. break;
  36. }
  37. }
  38. } catch(IOException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. //接收和发送数据
  43. public void talk() throws IOException {
  44. socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
  45. while (selector.select() > 0 ) {
  46. Set readyKeys = selector.selectedKeys();
  47. Iterator it = readyKeys.iterator();
  48. while (it.hasNext()) {
  49. SelectionKey key = null;
  50. try {
  51. key = (SelectionKey) it.next();
  52. it.remove();
  53. if (key.isReadable()) {
  54. receive(key);
  55. }
  56. if (key.isWritable()) {
  57. send(key);
  58. }
  59. } catch(IOException e) {
  60. e.printStackTrace();
  61. try {
  62. if(key != null) {
  63. key.cancel();
  64. key.channel().close() ;
  65. }
  66. } catch(Exception ex) {
  67. e.printStackTrace();
  68. }
  69. }
  70. }
  71. }
  72. }
  73. public void send(SelectionKey key) throws IOException {
  74. //发送sendBuffer的数据
  75. SocketChannel socketChannel = (SocketChannel)key.channel();
  76. synchronized(sendBuffer) {
  77. sendBuffer.flip(); //把极限设为位置,把位置设为0
  78. socketChannel.write(sendBuffer); //发送数据
  79. sendBuffer.compact(); //删除已经发送的数据
  80. }
  81. }
  82. public void receive(SelectionKey key) throws IOException {
  83. //接收EchoServer发送的数据,把它放到receiveBuffer
  84. //如果receiveBuffer有一行数据,就打印这行数据,然后把它从receiveBuffer删除
  85. SocketChannel socketChannel = (SocketChannel) key.channel();
  86. socketChannel.read(receiveBuffer):
  87. receiveBuffer.flip();
  88. String receiveData = decode (receiveBuffer);
  89. if(receiveData.indexOf("\n") == -1) return;
  90. String outputData = receiveData.substring(0, receiveData.indexOf("\n") + 1):
  91. System.out.print(outputData);
  92. if(outputData.equals("echo:bye\r\n")) {
  93. key.cancel():
  94. socketChannel.close();
  95. selector.close();
  96. System.exit(0);
  97. }
  98. ByteBuffer temp = encode(outputData);
  99. receiveBuffer.position(temp.limit());
  100. receiveBuffer.compact(): //删除已经打印的数据
  101. }
  102. //解码
  103. public String decode(ByteBuffer buffer) {
  104. CharBuffer charBuffer= charset.decode(buffer);
  105. return charBuffer.toString();
  106. }
  107. //编码
  108. public ByteBuffer encode(String str) {
  109. return charset.encode(str);
  110. }
  111. }

Java 网络编程 —— 实现非阻塞式的客户端的更多相关文章

  1. Java网络编程 -- NIO非阻塞网络编程

    从Java1.4开始,为了替代Java IO和网络相关的API,提高程序的运行速度,Java提供了新的IO操作非阻塞的API即Java NIO.NIO中有三大核心组件:Buffer(缓冲区),Chan ...

  2. 网络编程之非阻塞connect编写

    一.connect非阻塞编写 TCP连接的建立涉及到一个三次握手的过程,且socket中connect函数需要一直等到客户接收到对于自己的SYN的ACK为止才返回, 这意味着每 个connect函数总 ...

  3. Java网络编程(TCP协议-服务端和客户端交互)

    客户端: package WebProgramingDemo; import java.io.IOException; import java.io.InputStream; import java. ...

  4. Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库

    一.NIO非阻塞式网络通信 1.阻塞与非阻塞的概念  传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...

  5. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  6. Java网络编程 -- BIO 阻塞式网络编程

    阻塞IO的含义 阻塞(blocking)IO :阻塞是指结果返回之前,线程会被挂起,函数只有在得到结果之后(或超时)才会返回 非阻塞(non-blocking)IO :非阻塞和阻塞的概念相对应,指在不 ...

  7. Java IO(3)非阻塞式输入输出(NIO)

    在上篇<Java IO(2)阻塞式输入输出(BIO)>的末尾谈到了什么是阻塞式输入输出,通过Socket编程对其有了大致了解.现在再重新回顾梳理一下,对于只有一个“客户端”和一个“服务器端 ...

  8. Socket-IO 系列(三)基于 NIO 的同步非阻塞式编程

    Socket-IO 系列(三)基于 NIO 的同步非阻塞式编程 缓冲区(Buffer) 用于存储数据 通道(Channel) 用于传输数据 多路复用器(Selector) 用于轮询 Channel 状 ...

  9. NIO非阻塞式编程

    /** * NIO非阻塞式编程<p> * 服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件. * 我们以服务端 ...

  10. Java基础知识强化之多线程笔记07:同步、异步、阻塞式、非阻塞式 的联系与区别

    1. 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就必须先得到返回值了. 换句话话说,调用者主动等待这个"调用"的结果. 对于 ...

随机推荐

  1. jpa用findAll((Specification<GoodsSpu>) (root, criteriaQuery, criteriaBuilder) -> {})排序

    //需要用到的包import org.springframework.data.domain.Page;import org.springframework.data.domain.PageReque ...

  2. 基础练习:FJ的字符串

    问题描述 FJ在沙盘上写了这样一些字符串: A1 = "A" A2 = "ABA" A3 = "ABACABA" A4 = "AB ...

  3. 【scipy 基础】--稀疏矩阵

    稀疏矩阵是一种特殊的矩阵,其非零元素数目远远少于零元素数目,并且非零元素分布没有规律.这种矩阵在实际应用中经常出现,例如在物理学.图形学和网络通信等领域. 稀疏矩阵其实也可以和一般的矩阵一样处理,之所 ...

  4. H.264 和 H.265对比

    前言 H.264标准正式发布于2003年3月,距今已经20多年了,但它仍然是当下最流行的视频编解码标准. H.265正式发布于2013年4月.虽然H.265标准是围绕着H.264进行制定的,也保留了原 ...

  5. Modbus 转 PROFIBUS DP 应用场景 PM-160

    1)在网关PROFIBUS DP侧是一个PROFIBUSDP从站,在Modbus串口侧有Modbus主站.Modbus从站.通用模式可选:接口有RS232RS485.RS422三种可选. 2)通信方式 ...

  6. Linux MIPI 调试中常见的问题

    一.概述 做嵌入式工作的小伙伴知道,有时候程序编写没有调试过程中费时,之间笔记里有 MIPI 摄像头驱动开发的过程,有需要的小伙伴可以参考:Linux RN6752 驱动编写. 而我也是第一次琢磨 M ...

  7. Hdu4742 (CDQ分治)

    题意:给出n个三维点对(x,y,z),可随意排列,求三维非严格最长上升子序列长度和最长上升子序列数量. 输入格式:第一行为一整数T表示用例组数,每组用例第一行为一整数n表示点数,之后n行每行三个整数x ...

  8. Java+Selenium爬取高德POI边界坐标

    一.写在前面 关于爬取高德兴趣点边界坐标网上有几篇文章介绍实现方式,总的来说就是通过https://www.amap.com/detail/get/detail传入POI的ID值获取数据,BUT,如果 ...

  9. [ABC261A] Intersection

    Problem Statement We have a number line. Takahashi painted some parts of this line, as follows: Firs ...

  10. Ubuntu 22.04 LTS 安装lnmp

    Ubuntu 22.04 LTS 安装最新稳定版本nginx.mysql5.7和php7.2 全部apt-get安装,就是快,迅速.前提是需要在有网络环境的情况下哈!! 操作系统版本:Ubuntu 2 ...