(JAVASE)CSFrameWork详解(Client及ClientConversation)
ClientConversation继承于communication,所以在该层就该将抽象方法具体实现,完善其对信息的具体操作。
client是提供给app层调用的类,其包含的方法都是发出请求,实际是调用了conversation里的方法通过communication向服务端发信息。
conversation层处理信息的发出和接受,发出是提供给client层并进一步给app层使用的,信息的接受就是完成dealNetMessage抽象方法的实现,对应不同的command调用适配器中的不同方法。
首先对于所有的客户端操作都先用接口表示一下:
void serverOutOfRoom();
void afterConnectToServer();
void serverAbnormalDrop();
void toOne(String source, String message);
void toOther(String source, String message);
boolean confirmOffline();
void beforeOffline();
void afterOffline();
void serverForceDown();
void killByServer(String reason);
void dealResponse(String action, String message);
分别是:
连接到服务器之后需要进行的操作;
对应服务端异常掉线的处理;
信息单发及群发;
确认当前是否离线;
离线前和离线后的操作;
服务器强制宕机后的处理;
被服务器强制下线的操作;
对服务器答复的处理。
但是对接口的直接使用,会将成堆未实现的方法一股脑放到程序中,而实际应用应该是对不同情景,取出对应的处理方法,这就引入适配器的使用。
适配器:
public class ClientActionAdapter implements IClientAction {
public ClientActionAdapter() {
}
@Override
public void serverOutOfRoom() {}
@Override
public void serverAbnormalDrop() {}
@Override
public void toOne(String source, String message) {}
@Override
public boolean confirmOffline() {
return true;
}
@Override
public void afterOffline() {}
@Override
public void beforeOffline() {}
@Override
public void toOther(String source, String message) {}
@Override
public void serverForcedown() {}
@Override
public void killByServer(String reason) {}
@Override
public void afterConnectToServer() {}
@Override
public void dealResponse(String action, String parameter) {}
}
实际适配器就是对接口的空实现,在后期使用方法:
private IClientAction clientAction;
this.clientAction = new ClientActionAdapter();
首先将该接口作为成员加入类中,接着用适配器将该成员实现。
this.client.getClientAction().serverOutOfRoom();
之后像上述使用。
注:主要用于接受信息后从适配器中提取需要的方法进行处理。
先完成ClientConversation中信息发出的函数及构造方法:
private Client client;
private String id;
public ClientConversation(Socket socket, Client client) throws IOException {
super(socket);
this.client = client;
}
ClientConversation有两个成员,id的获取在连接到服务器之后由服务器发回。
其构造方法是沿用父类communication。
发送信息:
void sendRequest(String action, String parameter) {
send(new NetMessage()
.setCommand(ENetCommand.REQUEST)
.setSource(id)
.setTarget(Server.SERVER)
.setAction(action)
.setMessage(parameter));
}
void offline() {
send(new NetMessage()
.setCommand(ENetCommand.OFFLINE));
close();
}
void toOne(String targetId, String message) {
send(new NetMessage()
.setCommand(ENetCommand.TO_ONE)
.setSource(id)
.setTarget(targetId)
.setMessage(message));
}
void toOther(String message) {
send(new NetMessage()
.setCommand(ENetCommand.TO_OTHER)
.setSource(id)
.setTarget(Server.SERVER)
.setMessage(message));
}
void messageToServer(String message) {
send(new NetMessage()
.setCommand(ENetCommand.MESSAGE_TO_SERVER)
.setSource(id)
.setTarget(Server.SERVER)
.setMessage(message));
}
对应枚举命令定义所需方法即可。
上述方法就是给Client调用的方法。
Client构造:
private String ip;
private int port;
private Socket socket;
private ClientConversation conversation;
private IClientAction clientAction;
private IRequestResponseAction responseAction;
public static final Gson gson = new GsonBuilder().create();
public Client() {
this.ip = INetConfig.ip;
this.port = INetConfig.port;
this.clientAction = new ClientActionAdapter();
this.responseAction = new RequestResponseAction();
}
Client调用:
public void sendRequest(String action, String parameter) {
this.conversation.sendRequest(action, parameter);
}
public void offline() {
if (this.clientAction.confirmOffline()) {
this.clientAction.beforeOffline();
this.conversation.offline();
this.clientAction.afterOffline();
}
}
public void toOne(String targetId, String message) {
this.conversation.toOne(targetId, message);
}
public void toOther(String message) {
this.conversation.toOther(message);
}
public void messageToServer(String message) {
this.conversation.messageToServer(message);
}
连接服务器:
public boolean connectToServer() {
try {
this.socket = new Socket(this.ip, this.port);
this.conversation = new ClientConversation(socket, this);
return true;
} catch (IOException e) {
}
return false;
}
连接到服务器的操作就是依据当前配置文件的ip和端口,新建一个信息交互通道,并且将该通道和Client本身加到conversation中。
接收信息的反馈处理:
public void dealNetMessage(NetMessage netMessage) {
ENetCommand command = netMessage.getCommand();
switch (command) {
case OUT_OF_ROOM:
// 应该由APP层的客户端逻辑,处理OutofRoom!
this.client.getClientAction().serverOutOfRoom();
close();
break;
case ID:
this.id = netMessage.getTarget();
this.client.getClientAction().afterConnectToServer();
break;
case TO_ONE:
// 客户端接收到服务器发送的另一个客户端的单聊信息,
// 这个信息的处理应该由APP层决定,本工具没有处置权利!
this.client.getClientAction().toOne(netMessage.getSource(), netMessage.getMessage());
break;
case TO_OTHER:
this.client.getClientAction().toOther(netMessage.getSource(), netMessage.getMessage());
break;
case FORCEDOWN:
this.client.getClientAction().serverForcedown();
close();
break;
case KILL_CLIENT:
this.client.getClientAction().killByServer(netMessage.getMessage());
close();
break;
case RESPONSE:
try {
this.client.getResponseAction().dealResponse(
netMessage.getAction(), netMessage.getMessage());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
default:
break;
}
这段就是根据客户端接收到的命令字段,判断对应的操作。
利用this.client.getResponseAction().调用对应方法。
推荐阅读
-
(JAVASE)CSFrameWork详解(NetMessage)
-
(JAVASE)CSFrameWork详解(Client及ClientConversation)
-
(JAVASE)CSFrameWork详解(communication层及笼统概述)
-
Spring Cloud Config Client超时及重试示例详解
-
Spring Cloud Config Client超时及重试示例详解
-
Docker-client for python详解及简单示例
-
Docker-client for python详解及简单示例
-
(JAVASE)CSFrameWork详解(Server及ServerConversation、观察者视角)