- package houlei.csdn.keepalive;
- 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維持連接包";
- }
- }
- package houlei.csdn.keepalive;
- 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();
- }
- }
- }
- }
- }
- package houlei.csdn.keepalive;
- 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());
- }
- }
- }
大致解釋一下什么意思:
長連接的維持,是要客戶端程序,定時向服務端程序,發送一個維持連接包的。
如果,長時間未發送維持連接包,服務端程序將斷開連接。
客戶端:
通過持有Client對象,可以隨時(使用sendObject方法)發送Object給服務端。
如果keepAliveDelay毫秒(程序中是2秒)內未發送任何數據,則,自動發送一個KeepAlive對象給服務端,
用於維持連接。
由於,我們向服務端,可以發送很多不同的對象,服務端也可以返回不同的對象。
所以,對於返回對象的處理,要編寫具體的ObjectAction實現類進行處理。
通過Client.addActionMap方法進行添加。這樣,程序會回調處理。
服務端:
由於客戶端會定時(keepAliveDelay毫秒)發送維持連接的信息過來,所以,服務端要有一個檢測機制。
即當服務端receiveTimeDelay毫秒(程序中是3秒)內未接收任何數據,則,自動斷開與客戶端的連接。
ActionMapping的原理與客戶端相似(相同)。
通過添加相應的ObjectAction實現類,可以實現不同對象的響應、應答過程。
