C/S开发框架之最外层(服务器端和客户端)的实现
最外层是服务器端和客户端,也就是直接由使用C/S框架的用户使用的两个类。
客户端—Client类
与服务器端一样,先实现客户端最基本的功能:
1.连接服务器(若连接失败,则应告知APP层);
2.服务器异常宕机处理
…
连接服务器
连接服务器是客户端第一要务,如果服务器都没有连接上,那么,后续操作根本就谈不上了。
public boolean connectToServer() throws ClientActionNotSetException {
if (clientAction == null) {
throw new ClientActionNotSetException("未设置Client Action!");
}
try {
this.socket = new Socket(ip, me.getPort());
this.clientConversation = new ClientConversation(this, socket);
} catch (Exception e) {
return false;
}
return true;
}
通过返回值可以知道连接成功与否,这需要告知APP层,那么,APP如何知道呢?
而对于服务器端异常宕机的处理呢,我们知道,对于服务器异常宕机的识别,是在ClientConversation类中实现的,Client类得知服务器异常掉线的消息,作为工具是无法处理的,或者说,对于”服务器异常掉线“这种情况,我们只能告知APP层,由APP层具体处理。
那么,问题就是,如何告知APP层呢?
我们现在做的是工具,APP当然是未来使用这个工具的用户编写的,所以,我们可以提供一个接口,APP客户端必须实现这个接口,而Client类中将接口对象作为成员,这样就可以将App层的”网络响应“代码”装配“到Client中。
package com.mec.csframework.core;
public interface IClientAction {
void serverOutOfRoom();
void afterConnectToServer();
boolean confirmOffline();
void beforeOffline();
void afterOffline();
void serverAbnormalDrop();
void serverForcedown();
void dealToOne(String sourceId, String message);
void dealToOther(String sourceId, String message);
}
我们可以看到,IClientAction接口中的方法都是需要用户具体去实现的方法。
同时提供一个接口的适配器ClientActionAdapter:
package com.mec.csframework.core;
public class ClientActionAdapter implements IClientAction {
public ClientActionAdapter() {
}
@Override
public void afterConnectToServer() {
}
@Override
public void serverOutOfRoom() {
}
@Override
public boolean confirmOffline() {
return true;
}
@Override
public void afterOffline() {
}
@Override
public void serverAbnormalDrop() {
}
@Override
public void dealToOne(String sourceId, String message) {
}
@Override
public void dealToOther(String sourceId, String message) {
}
@Override
public void serverForcedown() {
}
@Override
public void beforeOffline() {
}
}
这个适配器可以什么都不用做,相当于一个”空壳子“,因为具体实现工作是在APP层中具体实现的,APP层中可以以内部类继承于ClientActionAdapter的实现方式,也可以以匿名内部类的方式。
这里给一个内部类实现的例子:
class connectToServer extends ClientActionAdapter {
public connectToServer() {
}
@Override
public void serverOutOfRoom() {
ViewTool.showMessage(jfrmClientView, "服务器已满,请稍后尝试!");
try {
exitView();
} catch (FramelsNullException e) {
e.printStackTrace();
}
}
@Override
public void afterConnectToServer() {
ClientLogin clientLogin = new ClientLogin(client);
try {
clientLogin.showView();
} catch (FramelsNullException e1) {
e1.printStackTrace();
}
try {
exitView();
} catch (FramelsNullException e) {
e.printStackTrace();
}
}
}
同样,可以编写一个View界面简单测试一下服务器连接,当然这里为了简单起见,连接成功之后并没有执行上面代码的用户登录的操作,只是显示一下连接成功即可。下面是测试结果如下图:
Client类完整代码:
package com.mec.csframework.core;
import java.net.Socket;
import java.net.UnknownHostException;
import com.mec.csframework.action.DefaultActionProcessor;
import com.mec.csframework.action.IActionProcessor;
import com.mec.util.PropertiesParser;
public class Client {
private String ip;
private Socket socket;
private ClientConversation clientConversation;
private IClientAction clientAction;
private NetNode me;
private IActionProcessor actionProcessor;
public Client() throws UnknownHostException {
this.ip = INetBaseConfig.DEFAULT_IP;
this.me = new NetNode().setPort(INetBaseConfig.DEFAULT_PORT);
this.actionProcessor = new DefaultActionProcessor();
}
IClientAction getClientAction() {
return clientAction;
}
NetNode getMe() {
return me;
}
IActionProcessor getActionProcesser() {
return this.actionProcessor;
}
public void initClient(String configPath) {
PropertiesParser pp = new PropertiesParser();
pp.loadProperties(configPath);
String ip = pp.value("ip");
if (ip != null && ip.length() > 0) {
this.ip = ip;
}
String strPort = pp.value("port");
if (strPort != null && strPort.length() > 0) {
this.me.setPort(Integer.valueOf(strPort));
}
}
public void initClient() {
initClient("/net.cfg.properties");
}
public void sendMessageToServer(String message) {
this.clientConversation.sendMessageToServer(message);
}
public void sendRequest(String action, String parameter) {
this.clientConversation.sendRequest(action, action, parameter);
}
public void sendRequest(String request, String response, String parameter) {
this.clientConversation.sendRequest(request, response, parameter);
}
public void setClientAction(IClientAction clientAction) {
this.clientAction = clientAction;
}
public void setIp(String ip) {
this.ip = ip;
}
public void setPort(int port) {
this.me.setPort(port);
}
public String getId() {
return this.clientConversation.getId();
}
public void offline() {
if (clientAction.confirmOffline()) {
clientAction.beforeOffline();
clientConversation.offline();
clientAction.afterOffline();
}
}
public boolean connectToServer() throws ClientActionNotSetException {
if (clientAction == null) {
throw new ClientActionNotSetException("未设置Client Action!");
}
try {
this.socket = new Socket(ip, me.getPort());
this.clientConversation = new ClientConversation(this, socket);
} catch (Exception e) {
return false;
}
return true;
}
public void toOne(String id, String message) {
clientConversation.toOne(id, message);
}
public void toOther(String message) {
clientConversation.toOther(message);
}
}
至此,结合上篇文章,关于CSFramework的最外层,即Server和Client类的功能简述结束。
下一篇将继续CSFramework的另一核心部分,关于action和分发器的实现。