-
核心功能
支持面向流通信主要抽象是
Connection
接口。
通过
IBlockingConnection
或者
IN
onblockingConnection
对象进行数据的读写。在
< br>record
或者
bulk
状态
中,
Connection
对象提供了对于特定数据类型的几个
方便方法。
Connection
实
现了
包中的
GatheringByt
eChannel
和
WritableByteChannel
接口,如果
InputStream
或
者
OutputStream
对象被需要,可
< br>以使用
utStream(
和
putStream(
包装
channel
对象,因为
经典的流只有在
IBlockingConnection
映射到经典的
InputStream
中时才有阻塞行
p>
为。
提供的其他类型方法主要是控制连接
行为和获取连接信息的方法。比如,远
程链接点信息可以获取到,
连接的数据冲刷行为可以被控制。
这些方法都不是线
程安全的
。
与
IBlockingConne
ction
不同的是,
INonBlockingConnec
tion
在调用
read
方法
直接返回。
将
IDataHandler
对象赋给
INonBlockingConnection
对象可以使其在新
数据到来时被通知。当对应的事件发生时,
IDataHandler
对象的回调函数会被调
用
。除了
IDataHandler
也存在
IConnectionHandler
对象。
服务器端在
INonblockingConnection
接口上处理接入连接。
1
、示例:简单
TCP
服务器
首先定义实现了需要的接口(比如,
IDat
aHandler
,
IConnectHandler
,
IIdleTimeoutHandler
或
者
IConnectionTimeoutHandler
)<
/p>
,这个
DataHandler
会在从<
/p>
连接上接收到数据时被调用。
classEchoHandler implements
IDataHandler {
publicbooleanonData(INon
BlockingConnectionnbc)
throwsIOException,
BufferUnderflowException,
MaxReadSizeExceededException {
String data =
ringByDelimiter(
(data +
return true;
}
}
然后创建一个服务器实例,并
将上面的
DataHandler
赋给它
// creates the server by passing over
the port number & handler
IServersrv =
new Server(8090, new EchoHandler());
// run it within the current thread.
();
// the call will not return
// ... or start it by using a dedicated
thread
专用线程
(); //
returns after the server has been started
< br>与
run
方法对应的,服务器的
start
方法创建一个专用的线程来运行服务器。
start
方法在内部阻塞知道服务器启动,
为了确保服务器在执行其他进
一步操作前
被启动,这是比较好的方法。
执行服务器的
close
方法来优雅的关闭服务器。就像其
他面向连接的框架,
服务器实现了
le
接口
2
、
DataHandler
的
onDat
a
方法的语义分析
IDataHan
dler
的
onData
方法会在数据
分片被接收后直接调用。要注意的是,
在网络层,数据可以被分解成若干个
TCP
片段也可能被组合打包成一个
TCP
报
文。
在客户端执行类似于
(
“
hello
”
)
的写操作,
并不意味着一个
TCP
报文到达服务器端。
xSocket
通过内部的读缓冲区缓冲接收到的网络数据来隐藏
网络行为。
在没有足够数据可用的情况下,数据分片会导致
NonBl
ockingConnection
的
read
方法抛出
BufferUnderflowException
异常。根据运行模式,在一个挂起的
onData
方法
调用期间没有数据会在网络层被收到。通过使用
NONTHREADED
模式,
xSocket
的内部网络
I/O
线程执行
onDataMethod
所以不能读取网络层数据。
BufferUnder
flowException
异常不处理是一个惯用的方法,
x
Socket
会在
onData
方法返
回时处理这个异常。
classEchoHandler
implements IDataHandler {
//
this method will be called each time when data
fragments have been
received
publicbooleanonData(INonBlockingConnectionnbc)
throwsIOException,
ClosedChannelException,
BufferUnderflowException,
MaxReadSizeExceededException {
// don't handle the
BufferUnderflowException, xSocket will swallow it
byte[] bytes =
tesByLength(500);
//...
return true;
}
}
因为没有读到的数据在
xSock
et
的内部缓冲内,
onData
方法
会被再次调用。
也就是说,
onData
方法会在没有新的网络数据包到达时调用,
因为
xSocke
t
的内
部读缓冲区是不空的。这个循环会在内部缓冲区为空或者
onData
方法读不到数
据时结束。
xSocket
在每次调用
onDat
a
方法后检查内部读缓冲区是否被修改
(新
的网络数据到达,或者数据被读出)
,从而决定是不是要再次调用
< br>onData
。
当连接关闭时
,
onData
方法也会被调用。与处理缓冲区的
underflow
异常一
样,
closedChannelException
也是不处理的,实现
IDisconnectHandler
来检测连接
关闭。
3
、写阻塞客户端
< br>在客户端,使用
IBlockingConnection
可以简化套接字处理。与
NonBlockingconnection
不同的是,
BlockingConnection
不支持回调处理。
IBlockingConnectionbc = new
BlockingConnection(host, port);
String req =
(req +
// read the whole logical
part by waiting (blocking) until
// the required data have been received
String res =
ringByDelimiter(
assert
((res));
4
、写非阻塞客户端
执行阻塞客户端的读方法,调用会在数据接收到或者超时事件发生后返回。
为了
避免这种情况,客户端需要定义处理
Handler
,当网络事
件发生后被调用。
(
IDataHandler
,
IDisconnectHandler
)
// defining the client handler
(here as a anonymous inner class)
IDataHandlerclientHandler = new
IDataHandler() {
publicbool
eanonData(INonBlockingConnectionnbc)
throwsIOException,
BufferUnderflowException,
MaxReadSizeExceededException {
//
read the whole logical part or throwing a
BufferUnderflowException
String res =
ringByDelimiter(
//...
return true;
}
};
// opening
the connection
INonBlockingConnectionnbc = new
NonBlockingConnection(host, port,
clientHandler);
(
// do something else. Receiving data
causes that the client
//
handler's onData method will be called (within a
dedicated thread)
//...
5
、使用
blocking
Connection
包装
non-blocking
Connection
xSocket
在内部使用
INonblockingConnection
实现
IBlockingConnection.
。
也就
是说,
BlockingConnection
是带有阻塞行为的
read
方法的包装,于是
NonblockingConnection
可以随时变成
< br>BlockingConnection
。
INonBlockingConnectionnbc= ...
// wrapping an existing
non-blocking connection by a BlockingConnection
IBlockingConnectionbc = new
BlockingConnection(nbc);
t();
//...
6
、在服务端包装非阻塞
Connection
在多数情况
下,
NonblockingConnection
在服务端使
用,如果服务器端需要一
个
BlockingConnecti
on
,
可以通过包装
NonBlock
ingConnection
的方式创建。
包装
非阻塞
Connection
会导致赋给其的
Handler
在内部被移除。典型的是
onC
onnect
方法会在服务端创建一个
BlockingCon
nection
。
...
classConnectHandler implements
IConnectHandler {
publicbooleanonConnec
t(INonBlockingConnectionnbc) throws IOException {
IBlockingConnectionbc = new
BlockingConnection(nbc);
//
return true;
}
...
7
、处理连接
通过实现
IConnectHandler
接口,
onConnect
回调用法会被调用。如果一个新
连接简历,
这个方法会被调用且仅被调用一次。
一般而言,<
/p>
这个方法会被用来对
新连接进行安全检查,修改连接属性,准备资
源,设置回联或者发送欢迎信息。
在这个方法读取数据是不推荐的,因为数据不一定准备
好。
class Handler implements
IDataHandler, IConnectHandler {
publicbooleanonConnect(INonBlockingConnection
nbc) throws IOException {
//... e.g. open resources
return true;
}
<
/p>
publicbooleanonData(INonBlockingConnecti
onnbc) throws IOException {
//...
return true;
}
}
8
、处理连接断开
< br>如果
Handler
实现了
ID
isconnectHandler
接口,
onDisconn
ect
会在连接终止的
时候调用
(不管
是当前进程终止连接或者远程终止)
,
尽管连接通过
onDisconnect
方法被当作参数传递,
但是任何读写操作都是不可以进行,
因为连接已经不存在。
三种关闭的情况:
A
、客户端主动关闭。这种情况下
onDisconnect
被直接调用
B
、连接损坏或者不
恰当的关闭,并且被
java
虚拟机检测到损坏连接。这种
p>
情况下,
onDisconnect
会在检
测到损坏连接时调用。
C
、连接损坏
或者不恰当关闭,但是没有被
java
虚拟机检测到。这种情况
下
需要实现
IIdleTimeoutHandler
和
IConnectionTimeoutHandler
接口,因为
onDisconnect
不会被调用。
class Handler implements
IDataHandler, IDisconnectHandler {
publicbooleanonDisconnect(INonBlockingConn
ectionnbc) throws IOException {
//... e.g. closing open resources
return true;
}
<
/p>
publicbooleanonData(INonBlockingConnecti
onnbc) throws IOException
ByteBuffer[]
data = teBufferByDelimiter(
// print out the received
data
ByteBuffer[] copy = new ByteBuffer[];
for (inti = 0; i<; i++) {
copy[i] = data[i].duplicate();
}
n(ng(copy));
//...
return
true;
}
}
在
连接断开的情况下,
IDataHandler
也被调用(在调
用
IDisconnectHandler
之前)
。与本地套接字读取一样,如果连接已经关闭,
INonblockingC
onnection
的
available
方法返回
-1
。
进行读取,
会排除
ClosedChannelException
,
如果不处理会
被
xSoc
ket
自动处理。
8
、异步连接
一般的创建阻塞和非阻塞连接都是同步的过程,
也就意味着在创建完成后立
即可以调用读写方法。不过,一些客户端的非阻塞连接在创建时包含了一个
waitForConnect
的参数,如果这个参数被设置为
false
,连接创建者不等待连接完
成建立就直接返回。下面
展示了如何异步创建连接。同样的,
Handler
对象需要<
/p>
是想
IConnectionExceptionHandler
来处理连接异常。
class
Handler implements IConnectHandler, IDataHandler,
IConnectExceptionHandler {
publicbooleanonConnect(INonBlockingConn
ectionnbc) throws IOException {
(
//...
return true;
publicbooleanonConnectExcep
tion(INonBlockingConnectionnbc,
IOExceptionioe) throws IOException {
//...
return true;
}
pu
blicbooleanonData(INonBlockingConnectionnbc)
throws IOException {
//...
return true;
}
}
Handler hdl = new Handler();
INonBlockingConnectionnbc =
new
NonBlockingConnection(ame(host),
port, hdl, false, 2000);
//...
// write operations
are only valid after the connection has been
established which
is indicated by the
onConect() callback
如果在创建非阻塞方法返回后立即调用
p>
write
方法,由于无法预测连接是否
建
立完成则会出现竞争条件。
onConnect
方法的调用标志
着连接的完成建立。
10
、处理超时
xSocket
支持连接超时和空闲超时。连接超时定义了连接的最长生命周期,<
/p>
与流量无关,
连接会在超出连接事件后被关闭。
< br>空闲超时定义了在没有数据接收
时的最长空闲时间,
为了
防止没有响应的连接浪费资源,
一旦连接空闲时间超时
就会被关
闭。默认的的超时时间是一个最大值,大概是
24
天。
连接的超时事件可以被用户处理。通过实现
I
IdleTimeoutHandler
和
IConnecti
onTimeoutHandler
,对应的
onconnec
tionTimeout
和
onIdleTimeout
方法
会被调用。如果这些方法返回
true<
/p>
,表明这些事件已经被处理,连接就不会被想
Socket
关闭。如果返回
false
,
xSocket
则会关闭这些连接。
连接的空闲超时时间可以针对每一个连接调用
setConnectionti
meoutsec()
和
setIdletimeoutSec
()
方法设定,同样的也调用这些方法来重设。例如超时在一个超
时回调方法中设定并且返回
true
,
那么这个超时事件就会表现的像从来没有发生
过。
服务端的默认超时行为可以通过服务器端的超时设置函数修改。
// the handler
class Handler
implements IDataHandler, IIdleTimeoutHandler,
IConnectionTimeoutHandler {
publicbooleanonConnectionTimeout(INonBl
ockingConnectionnbc) throws
IOException
{
(
();
return true;
//
prevent, that xSocket also closes the connection
}
pu
blicbooleanonIdleTimeout(INonBlockingConnectionnbc
) throws IOException
{
(
eTimeoutMillis(30 * 1000); // resets
the timeout counter
return true;
// prevent, that xSocket
closes the connection
}
publicbooleanonData(INonBlo
ckingConnectionnbc) throws IOException {
//...
return
true;
}
}
// and the server
IServer
server = new Server(8090, new Handler());
eTimeoutMillis(30 * 1000);
// set the
default idle timeout for
server-side
connections
();
11
、回调方法的同步
onConnect
和
onData
这样的回调方法会根据连接同步处理,也就是说对伊同
一个连接,如果
onConnect
不执行完成,那么用户也不会调用
< br>onData
。
class
Handler implements IConnectHandler, IDataHandler {
publicbooleanonConnect(INon
BlockingConnectionnbc) throws IOException {
(
//...
// DO NOT DO THIS!
// this causes that
onData() will never be called because executing of
//
callback methods is synchronized based on the
connection
while (true) {
try {
(1000);
} catch
(InterruptedException ignore) {
}
(
}
// You could define a TimerTask and run
it within a Timer (thread)
// to implement the
return true;
}
pu
blicbooleanonData(INonBlockingConnectionnbc)
throws IOException {
String msg =
ringByDelimiter(
//...
return true;
}
}
12
、定义连接作用域的
Handler
默认的
Handler
作用域是实例作用域(全局)
。也就是同一个
H
andler
可以用
于每一个新进入的连接。
< br>一个
Handler
通过实现
I
ConnectionScoped
接口来转变成
连接作用域的
。这个接口需要一个可以被用来为新连接创建专门
Handler
实例的
clone
方法。为了避免副作用,
< br>clone
方法需要实现成深度拷贝。
classSmtpHandler implements
IDataHandler, IConnectionScoped {
privateinthandledMessages = 0;
privateSessionDatasessionData = new
SessionData();
publicboolea
nonData(INonBlockingConnectionnbc) throws
IOException {
//...
return true;
}
// deep clone: all attributes beside
primitives, immutable or
// global manager/service
references have also to be cloned
public Object clone() throws
CloneNotSupportedException {
SmtpHandler copy = (SmtpHandler) ();
nData = (SessionData) ();
return copy;
}
}
通过声明
Handler
为连接作用域,
在支持深度拷贝的情况下,
Handler
的变量
自动变成连接指
定的。
同时除了这种显式的往连接发送数据的方法之外,
隐式的
方法也是支持的。
13
、绑定会话相关的数据到连接
<
/p>
一个可选的向连接分发会话数据的方法是直接附加数据。一般而言,这是推
荐的方法。一个连接支持附件特定连接的会话数据通过
setAttachme
nt(object)
,
getAttachment()
p>
方法。
classSmtpHandler implements
IConnectHandler, IDataHandler {
publicbooleanonConnect(INonBlockingConnection
nbc) throws IOException {
achment(new
SessionData());
return true;
}
publicbooleanonData(INonBlo
ckingConnectionnbc) throws IOException {
SessionDatasessionData = (SessionData)
achment();
//...
return true;
}
}
14
、运行时替换
Handler <
/p>
xSocket
支持在运行时替换
Han
dler
,这可以在服务器端为所有新进入的连接
应用新的
p>
Handler
。如果连接已经建立,可以调用
setHandler
方法来替换当前连
接的
Handler
。
classServerHandlerA implements
IDataHandler {
publicbooleanonData(INon
BlockingConnectionnbc) throws IOException {
String cmd =
ringByDelimiter(
if
((
dler(new ServerHandlerB());
} else {
(
}
return true;
}
}
在服务器端
Handler
赋给了
p>
server
,
这个
Handler
会赋值给每一个新进入的连
接,可以通过调用
setHandler
方法来替换。
classServerSideHandler implements
IDataHandler {
@Resource
private Server
server;
publicbooleanonData(INonBlockingConnection
connection) throws IOException
{
String cmd =
ringByDelimiter(
if
((
dler(new ServerHandlerB());
(
(
} else {
(
}
return true;
}
}
15
、示例:简单的基于长度的
Han
dler
为了应用基于长度的通信方法,
连接的
mark-support
可以使用,
这种情况下,
客户端首先写一个空的长度属性,
在写完内容数据之后,
写指针会移回到长度属
性域来覆盖长度属性域。
IBlockingConnectionbc = new
BlockingConnection(host, port);
oflush(false); // mark support requires
deactivated autoflush!
-
-
-
-
-
-
-
-
-
上一篇:英语国家地理概况
下一篇:c#连接数据库代码集合