之前我们已经看过了客户端的架构,现在我们来研究一个有代表性的客户端实例作为参考实现,即实例sumup client。我们将排除那些可以直接重复照搬的代码,而只关注最重要的组成部分,以下是这个客户端的核心代码:
public static void main(String[] args) throws Throwable { NioSocketConnector connector = new NioSocketConnector(); connector.setConnectTimeoutMillis(CONNECT_TIMEOUT); if (USE_CUSTOM_CODEC) { connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SumUpProtocolCodecFactory(false))); } else { connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); } connector.getFilterChain().addLast("logger", new LoggingFilter()); connector.setHandler(new ClientSessionHandler(values)); IoSession session; for (;;) { try { ConnectFuture future = connector.connect(new InetSocketAddress(HOSTNAME, PORT)); future.awaitUninterruptibly(); session = future.getSession(); break; } catch (RuntimeIoException e) { System.err.println("Failed to connect."); e.printStackTrace(); Thread.sleep(5000); } } // wait until the summation is done session.getCloseFuture().awaitUninterruptibly(); connector.dispose(); }
要创建一个客户端程序,需要完成以下内容:
- 创建一个连接器
- 创建一个过滤器链
- 创建一个IO处理程序IOHandler并添加到连接器中
- 绑定到需要连接的Server上
接下来,我们来详细的看每一个步骤:
1. 创建一个连接器:
NioSocketConnector connector = new NioSocketConnector();
通过以上代码我们就创建了一个基于NIO的Socket连接器。
2. 创建一个过滤器链:
if (USE_CUSTOM_CODEC) { connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SumUpProtocolCodecFactory(false))); } else { connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); }
为连接器添加各种过滤器到过滤器链中,此处我们只添加了一个ProtocolCoedc协议编码转换过滤器到过滤器链中。
3. 创建IO处理程序
connector.setHandler(new ClientSessionHandler(values));
此处我们创建了一个ClientSessionHandler 的实例,并设置其为该连接的处理程序。
4. 绑定到服务器
IoSession session; for (;;) { try { ConnectFuture future = connector.connect(new InetSocketAddress(HOSTNAME, PORT)); future.awaitUninterruptibly(); session = future.getSession(); break; } catch (RuntimeIoException e) { System.err.println("Failed to connect."); e.printStackTrace(); Thread.sleep(5000); } }
这一块是最重要的部分,进行连接远端的服务器,由于连接本身是异步的,因此我们使用类ConnectFuture,以便获取连接实际建立的时间。一旦连接建立,我们就可以获取一个连接该服务器的IOSession。之后,我们不管发送任何消息到服务器,都要将其写入到该Session中。而所有从服务器返回的响应或消息都会穿过这个过滤器链并最终在IOHandler中被处理。