1、核心功能支持面向流通信主要抽象是 Connection 接口。通过 IBlockingConnection 或者 INonblockingConnection 对象进行数据的读写。在 record 或者 bulk 状态中,Connection 对象提供了对于特定数据类型的几个方便方法。Connection 实现了 java.nio 包中的 GatheringByteChannel 和WritableByteChannel 接口,如果 InputStream 或者 OutputStream 对象被需要,可以使用 java.nio.Channels.newInputStream()和java.ni
2、o.Channels.newOutputStream()包装 channel 对象,因为经典的流只有在 IBlockingConnection 映射到经典的 InputStream 中时才有阻塞行为。提供的其他类型方法主要是控制连接行为和获取连接信息的方法。比如,远程链接点信息可以获取到,连接的数据冲刷行为可以被控制。这些方法都不是线程安全的。与 IBlockingConnection 不同的是,INonBlockingConnection 在调用 read 方法直接返回。将 IDataHandler 对象赋给 INonBlockingConnection 对象可以使其在新数据到来时被通知。当
3、对应的事件发生时,IDataHandler 对象的回调函数会被调用。除了 IDataHandler 也存在 IConnectionHandler 对象。服务器端在 INonblockingConnection 接口上处理接入连接。1、示例:简单 TCP 服务器首先定义实现了需要的接口(比如,IDataHandler,IConnectHandler,IIdleTimeoutHandler 或者IConnectionTimeoutHandler) ,这个 DataHandler 会在从连接上接收到数据时被调用。class EchoHandler implements IDataHandler pu
4、blic boolean onData(INonBlockingConnection nbc) throws IOException, BufferUnderflowException, MaxReadSizeExceededException String data = nbc.readStringByDelimiter(“rn“);nbc.write(data + “rn“);return true;然后创建一个服务器实例,并将上面的 DataHandler 赋给它/ creates the server by passing over the port number / run it w
5、ithin the current thread. srv.run(); / the call will not return/ . or start it by using a dedicated thread 专用线程srv.start(); / returns after the server has been started与 run 方法对应的,服务器的 start 方法创建一个专用的线程来运行服务器。start 方法在内部阻塞知道服务器启动,为了确保服务器在执行其他进一步操作前被启动,这是比较好的方法。执行服务器的 close 方法来优雅的关闭服务器。就像其他面向连接的框架,服务器
6、实现了 java.io.Closable 接口2、DataHandler 的 onData 方法的语义分析IDataHandler 的 onData 方法会在数据分片被接收后直接调用。要注意的是,在网络层,数据可以被分解成若干个 TCP 片段也可能被组合打包成一个 TCP报文。在客户端执行类似于 connection.write(“hello”)的写操作,并不意味着一个TCP 报文到达服务器端。xSocket 通过内部的读缓冲区缓冲接收到的网络数据来隐藏网络行为。在没有足够数据可用的情况下,数据分片会导致 NonBlockingConnection 的read 方法抛出 BufferUnder
7、flowException 异常。根据运行模式,在一个挂起的onData 方法调用期间没有数据会在网络层被收到。通过使用 NONTHREADED模式,xSocket 的内部网络 I/O 线程执行 onDataMethod 所以不能读取网络层数据。BufferUnderflowException 异常不处理是一个惯用的方法,xSocket 会在onData 方法返回时处理这个异常。class EchoHandler implements IDataHandler / this method will be called each time when data fragments have bee
8、n receivedpublic boolean onData(INonBlockingConnection nbc) throws IOException,ClosedChannelException, BufferUnderflowException, MaxReadSizeExceededException / dont handle the BufferUnderflowException, xSocket will swallow it byte bytes = nbc.readBytesByLength(500);/.return true;因为没有读到的数据在 xSocket 的
9、内部缓冲内,onData 方法会被再次调用。也就是说,onData 方法会在没有新的网络数据包到达时调用,因为 xSocket 的内部读缓冲区是不空的。这个循环会在内部缓冲区为空或者 onData 方法读不到数据时结束。xSocket 在每次调用 onData 方法后检查内部读缓冲区是否被修改(新的网络数据到达,或者数据被读出) ,从而决定是不是要再次调用onData。当连接关闭时,onData 方法也会被调用。与处理缓冲区的 underflow 异常一样,closedChannelException 也是不处理的,实现 IDisconnectHandler 来检测连接关闭。3、写阻塞客户端在
10、客户端,使用 IBlockingConnection 可以简化套接字处理。与NonBlockingconnection 不同的是,BlockingConnection 不支持回调处理。IBlockingConnection bc = new BlockingConnection(host, port);String req = “Hello server“;bc.write(req + “rn“);/ read the whole logical part by waiting (blocking) until / the required data have been receivedStr
11、ing res = bc.readStringByDelimiter(“rn“);assert (req.equals(res);4、写非阻塞客户端执行阻塞客户端的读方法,调用会在数据接收到或者超时事件发生后返回。为了避免这种情况,客户端需要定义处理 Handler,当网络事件发生后被调用。(IDataHandler,IDisconnectHandler)/ defining the client handler (here as a anonymous inner class)IDataHandler clientHandler = new IDataHandler() public boo
12、lean onData(INonBlockingConnection nbc) throws IOException, BufferUnderflowException, MaxReadSizeExceededException / read the whole logical part or throwing a BufferUnderflowExceptionString res = nbc.readStringByDelimiter(“rn“);/.return true;/ opening the connectionINonBlockingConnection nbc = new N
13、onBlockingConnection(host, port, clientHandler);nbc.write(“Hello“);/ do something else. Receiving data causes that the client / handlers onData method will be called (within a dedicated thread)/.5、使用 blocking Connection 包装 non-blocking ConnectionxSocket 在内部使用 INonblockingConnection 实现 IBlockingConne
14、ction.。也就是说,BlockingConnection 是带有阻塞行为的 read 方法的包装,于是NonblockingConnection 可以随时变成 BlockingConnection。INonBlockingConnection nbc = ./ wrapping an existing non-blocking connection by a BlockingConnectionIBlockingConnection bc = new BlockingConnection(nbc);bc.readInt();/.6、在服务端包装非阻塞 Connection在多数情况下,No
15、nblockingConnection 在服务端使用,如果服务器端需要一个 BlockingConnection,可以通过包装 NonBlockingConnection 的方式创建。包装非阻塞 Connection 会导致赋给其的 Handler 在内部被移除。典型的是onConnect 方法会在服务端创建一个 BlockingConnection。.class ConnectHandler implements IConnectHandler public boolean onConnect(INonBlockingConnection nbc) throws IOException IB
16、lockingConnection bc = new BlockingConnection(nbc); / return true;.7、处理连接通过实现 IConnectHandler 接口,onConnect 回调用法会被调用。如果一个新连接简历,这个方法会被调用且仅被调用一次。一般而言,这个方法会被用来对新连接进行安全检查,修改连接属性,准备资源,设置回联或者发送欢迎信息。在这个方法读取数据是不推荐的,因为数据不一定准备好。class Handler implements IDataHandler, IConnectHandler public boolean onConnect(INo
17、nBlockingConnection nbc) throws IOException /. e.g. open resourcesreturn true;public boolean onData(INonBlockingConnection nbc) throws IOException /.return true;8、处理连接断开如果 Handler 实现了 IDisconnectHandler 接口,onDisconnect 会在连接终止的时候调用(不管是当前进程终止连接或者远程终止) ,尽管连接通过onDisconnect 方法被当作参数传递,但是任何读写操作都是不可以进行,因为连接
18、已经不存在。三种关闭的情况:A、客户端主动关闭。这种情况下 onDisconnect 被直接调用B、连接损坏或者不恰当的关闭,并且被 java 虚拟机检测到损坏连接。这种情况下,onDisconnect 会在检测到损坏连接时调用。C、连接损坏或者不恰当关闭,但是没有被 java 虚拟机检测到。这种情况下需要实现 IIdleTimeoutHandler 和 IConnectionTimeoutHandler 接口,因为onDisconnect 不会被调用。class Handler implements IDataHandler, IDisconnectHandler public boolea
19、n onDisconnect(INonBlockingConnection nbc) throws IOException /. e.g. closing open resourcesreturn true;public boolean onData(INonBlockingConnection nbc) throws IOException ByteBuffer data = connection.readByteBufferByDelimiter(“rn“);/ print out the received data ByteBuffer copy = new ByteBufferdata
20、.length;for (int i = 0; i destroy it/ (it will not return to the pool)pool.destroy(bc); catch (Exception ignore) 22、Flushing默认情况下,autoflush 是开启的,在这种方式下写方法会直接将要写的数据发送到下层子系统中。通过调用连接的 setAutoFlush 方法来改变连接行为。autoflush 示例:/client-sideIBlockingConnection bc = new BlockingConnection(host, port);bc.write(te
21、xt + “n“);String response = bc.readStringByDelimiter(“n“);/server-sideclass ServerHandler implements IDataHandler public boolean onData(INonBlockingConnection nbc) throws IOException String text = nbc.readStringByDelimiter(“n“);nbc.write(text);nbc.write(“n“);return true;用户管理的 flush 示例:/client-sideIB
22、lockingConnection bc = new BlockingConnection(host, port);bc.setAutoflush(false);bc.write(text + “n“);bc.flush();String response = bc.readStringByDelimiter(“n“);/server-sideclass ServerHandler implements IConnectHandler, IDataHandler / set autoflush with false (this behaviour can also / be controlle
23、d by server settings)public boolean onConnect(INonBlockingConnection nbc) throws IOException nbc.setAutoflush(false);return true;public boolean onData(INonBlockingConnection nbc) throws IOException String text = nbc.readStringByDelimiter(“n“);/.nbc.write(text);nbc.write(“n“);/.nbc.flush();return tru
24、e;Autoflush 自动将写方法的数据刷入到子系统,flushmode 控制的 flush 的行为。如果设置为 ASYNC,那么数据就会以异步的方式传递到下层系统。因为使用了 WriteByteChannel 接口,write(ByteBuffer)和Write( ByteBuffer)会在某些条件下退出。使用 ASYNC 调用这样的方法会通过内部 I/O 进程异步读取。吐过字节缓存在调用写方法之后被操作,那么竞争条件会发生。除非在字节缓存不会在写方法之后被操作的情况下,write 才可以使用 ASYNC 调用。比如下面的情况,字节缓存会被重用被多次来复制数据,在这种情况下 ASYNC 是
25、不可以使用的。一旦使用,竞争条件就会发生。.File file = new File(filename);RandomAccessFile raf = new RandomAccessFile(file, “r“);ReadableByteChannel fc = raf.getChannel();IBlockingConnection connection = new BlockingConnection(host, port);/ using a copy buffer (which will be reused for the read operations)/ requires Flu
26、shMode SYNC which is default (for writing)! ByteBuffer copyBuffer = ByteBuffer.allocate(4096); int read = 0;while (read = 0) / read channelread = fc.read(copyBuffer);copyBuffer.flip();if (read 0) / write channelconnection.write(copyBuffer);if (copyBuffer.hasRemaining() copyBpact(); else copyBuffer.c
27、lear();26、性能推荐阻塞和非阻塞通用:使用直接写的 ByteBuffer 来读取数据,使用设置系统属性 usedirect 为 true,可以激活直接写。org.xsocket.connection.client.readbuffer.usedirect=trueorg.xsocket.connection.server.readbuffer.usedirect=true默认为 false,因为有些 Java 虚拟机实现中存在问题。阻塞和非阻塞通用:通过设置 autoflush 为 false,可以手工控制数据冲洗。因为 flush 操作在下层系统上执行写和同步操作,flush 操作是
28、代价很大的。尤其是在一个事务中执行多个写时,用户执行的 flush 操作可以提高性能。IBlockingConnection bc = .bc.setAutoflush(false);bc.write(header);bc.write(fragment1);bc.write(fragement2);/.bc.flush();27、配置服务器调用适当的设置器来动态配置参数。/ define the timeout, in which data have to be receivedsrv.setIdleTimeoutMillis(2 * 60 * 1000);/ define the timeo
29、ut for the connectionsrv.setConnectionTimeoutMillis(30 * 60 * 1000);/ set the default autoflush behaviour of the / server-side created connectionssrv.setAutoflush(false);同样可配置 work pool。Pool 可以执行 Handler 的回调方法(比如onData,onConnect) ,在从套接字读取数据之后,xSocket 的内部 Dispatcher 开始一个工作者线程池。Dispatcher 线程负责套接字读写和函数
30、回调。通过合适的设置方法设置 pool,通过 java.util.concurrent.Executor 接口实现。如果没有被设置,可以使用固定的线程池。srv.setWorkerpool(Executors.newFixedThreadPool(20);28、同步调用 Handler 方法Handler 的回调方法会在一个同步的上下文中调用也就是说对于同一个连接而言,回调方法的调用都是串行的。默认的额工作者线程执行回调方法,通过设置 Handler 执行模式为 NONTHREADED,Handler 的回调会被 xSocket 的内部线程池调用。这将提高性能和规模,因为线程切换的开销会被避免。