长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。
如果,长时间未发送维持连接包,服务端程序将断开连接。
客户端:
通过持有Client对象,可以随时(使用sendObject方法)发送Object给服务端。
如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则,自动发送一个KeepAlive对象给服务端,
用于维持连接。
由于,我们向服务端,可以发送很多不同的对象, 服务端也可以返回不同的对象 。
所以,对于返回对象的处理,要编写具体的ObjectAction实现类进行处理。
通过Client.addActionMap方法进行添加。这样,程序会回调处理。
服务端:
由于客户端会定时(keepAliveDelay毫秒)发送维持连接的信息过来,所以,服务端要有一个检测机制。
即当服务端receiveTimeDelay毫秒(程序中是3秒)内未接收任何数据,则,自动断开与客户端的连接。
ActionMapping的原理与客户端相似(相同)。
如果,长时间未发送维持连接包,服务端程序将断开连接。
客户端:
通过持有Client对象,可以随时(使用sendObject方法)发送Object给服务端。
如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则,自动发送一个KeepAlive对象给服务端,
用于维持连接。
由于,我们向服务端,可以发送很多不同的对象, 服务端也可以返回不同的对象 。
所以,对于返回对象的处理,要编写具体的ObjectAction实现类进行处理。
通过Client.addActionMap方法进行添加。这样,程序会回调处理。
服务端:
由于客户端会定时(keepAliveDelay毫秒)发送维持连接的信息过来,所以,服务端要有一个检测机制。
即当服务端receiveTimeDelay毫秒(程序中是3秒)内未接收任何数据,则,自动断开与客户端的连接。
ActionMapping的原理与客户端相似(相同)。
通过添加相应的ObjectAction实现类,可以实现不同对象的响应、应答过程。
import
java.io.Serializable;
import
java.text.SimpleDateFormat;
import
java.util.Date;
/**
* 维持连接的消息对象。
* <p>
* 创建时间:2010-7-18 上午12:22:09
* @author HouLei
* @since 1.0
*/
public
class
KeepAlive
implements
Serializable{
private
static
final
long
serialVersionUID = -2813120366138988480L;
/* 覆盖该方法,仅用于测试使用。
* @see java.lang.Object#toString()
*/
@Override
public
String toString() {
return
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
).format(
new
Date())+
"\t维持连接包"
;
}
}
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.ObjectInputStream;
import
java.io.ObjectOutputStream;
import
java.net.Socket;
import
java.net.UnknownHostException;
import
java.util.concurrent.ConcurrentHashMap;
/**
* C/S架构的客户端对象,持有该对象,可以随时向服务端发送消息。
* <p>
* 创建时间:2010-7-18 上午12:17:25
* @author HouLei
* @since 1.0
*/
public
class
Client {
/**
* 处理服务端发回的对象,可实现该接口。
*/
public
static
interface
ObjectAction{
void
doAction(Object obj,Client client);
}
public
static
final
class
DefaultObjectAction
implements
ObjectAction{
public
void
doAction(Object obj,Client client) {
System.out.println(
"处理:\t"
+obj.toString());
}
}
public
static
void
main(String[] args)
throws
UnknownHostException, IOException {
String serverIp =
"127.0.0.1"
;
int
port =
65432
;
Client client =
new
Client(serverIp,port);
client.start();
}
private
String serverIp;
private
int
port;
private
Socket socket;
private
boolean
running=
false
;
private
long
lastSendTime;
private
ConcurrentHashMap<Class, ObjectAction> actionMapping =
new
ConcurrentHashMap<Class,ObjectAction>();
public
Client(String serverIp,
int
port) {
this
.serverIp=serverIp;
this
.port=port;
}
public
void
start()
throws
UnknownHostException, IOException {
if
(running)
return
;
socket =
new
Socket(serverIp,port);
System.out.println(
"本地端口:"
+socket.getLocalPort());
lastSendTime=System.currentTimeMillis();
running=
true
;
new
Thread(
new
KeepAliveWatchDog()).start();
new
Thread(
new
ReceiveWatchDog()).start();
}
public
void
stop(){
if
(running)running=
false
;
}
/**
* 添加接收对象的处理对象。
* @param cls 待处理的对象,其所属的类。
* @param action 处理过程对象。
*/
public
void
addActionMap(Class<Object> cls,ObjectAction action){
actionMapping.put(cls, action);
}
public
void
sendObject(Object obj)
throws
IOException {
ObjectOutputStream oos =
new
ObjectOutputStream(socket.getOutputStream());
oos.writeObject(obj);
System.out.println(
"发送:\t"
+obj);
oos.flush();
}
class
KeepAliveWatchDog
implements
Runnable{
long
checkDelay =
10
;
long
keepAliveDelay =
2000
;
public
void
run() {
while
(running){
if
(System.currentTimeMillis()-lastSendTime>keepAliveDelay){
try
{
Client.
this
.sendObject(
new
KeepAlive());
}
catch
(IOException e) {
e.printStackTrace();
Client.
this
.stop();
}
lastSendTime = System.currentTimeMillis();
}
else
{
try
{
Thread.sleep(checkDelay);
}
catch
(InterruptedException e) {
e.printStackTrace();
Client.
this
.stop();
}
}
}
}
}
class
ReceiveWatchDog
implements
Runnable{
public
void
run() {
while
(running){
try
{
InputStream in = socket.getInputStream();
if
(in.available()>
0
){
ObjectInputStream ois =
new
ObjectInputStream(in);
Object obj = ois.readObject();
System.out.println(
"接收:\t"
+obj);
ObjectAction oa = actionMapping.get(obj.getClass());
oa = oa==
null
?
new
DefaultObjectAction():oa;
oa.doAction(obj, Client.
this
);
}
else
{
Thread.sleep(
10
);
}
}
catch
(Exception e) {
e.printStackTrace();
Client.
this
.stop();
}
}
}
}
}
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.ObjectInputStream;
import
java.io.ObjectOutputStream;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.util.concurrent.ConcurrentHashMap;
/**
* C/S架构的服务端对象。
* <p>
* 创建时间:2010-7-18 上午12:17:37
* @author HouLei
* @since 1.0
*/
public
class
Server {
/**
* 要处理客户端发来的对象,并返回一个对象,可实现该接口。
*/
public
interface
ObjectAction{
Object doAction(Object rev);
}
public
static
final
class
DefaultObjectAction
implements
ObjectAction{
public
Object doAction(Object rev) {
System.out.println(
"处理并返回:"
+rev);
return
rev;
}
}
public
static
void
main(String[] args) {
int
port =
65432
;
Server server =
new
Server(port);
server.start();
}
private
int
port;
private
volatile
boolean
running=
false
;
private
long
receiveTimeDelay=
3000
;
private
ConcurrentHashMap<Class, ObjectAction> actionMapping =
new
ConcurrentHashMap<Class,ObjectAction>();
private
Thread connWatchDog;
public
Server(
int
port) {
this
.port = port;
}
public
void
start(){
if
(running)
return
;
running=
true
;
connWatchDog =
new
Thread(
new
ConnWatchDog());
connWatchDog.start();
}
@SuppressWarnings
(
"deprecation"
)
public
void
stop(){
if
(running)running=
false
;
if
(connWatchDog!=
null
)connWatchDog.stop();
}
public
void
addActionMap(Class<Object> cls,ObjectAction action){
actionMapping.put(cls, action);
}
class
ConnWatchDog
implements
Runnable{
public
void
run(){
try
{
ServerSocket ss =
new
ServerSocket(port,
5
);
while
(running){
Socket s = ss.accept();
new
Thread(
new
SocketAction(s)).start();
}
}
catch
(IOException e) {
e.printStackTrace();
Server.
this
.stop();
}
}
}
class
SocketAction
implements
Runnable{
Socket s;
boolean
run=
true
;
long
lastReceiveTime = System.currentTimeMillis();
public
SocketAction(Socket s) {
this
.s = s;
}
public
void
run() {
while
(running && run){
if
(System.currentTimeMillis()-lastReceiveTime>receiveTimeDelay){
overThis();
}
else
{
try
{
InputStream in = s.getInputStream();
if
(in.available()>
0
){
ObjectInputStream ois =
new
ObjectInputStream(in);
Object obj = ois.readObject();
lastReceiveTime = System.currentTimeMillis();
System.out.println(
"接收:\t"
+obj);
ObjectAction oa = actionMapping.get(obj.getClass());
oa = oa==
null
?
new
DefaultObjectAction():oa;
Object out = oa.doAction(obj);
if
(out!=
null
){
ObjectOutputStream oos =
new
ObjectOutputStream(s.getOutputStream());
oos.writeObject(out);
oos.flush();
}
}
else
{
Thread.sleep(
10
);
}
}
catch
(Exception e) {
e.printStackTrace();
overThis();
}
}
}
}
private
void
overThis() {
if
(run)run=
false
;
if
(s!=
null
){
try
{
s.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
System.out.println(
"关闭:"
+s.getRemoteSocketAddress());
}
}
}