0
点赞
收藏
分享

微信扫一扫

小型C/S开发框架——CSFrameWork(一)

像小强一样活着 2022-02-03 阅读 47

小型C/S开发框架——CSFrameWork(一)

首先,要说明该框架是建立在一个多层次的系统下,共有三层——通信层,会话层最外层(服务器和客户端)。其中,通信层是最低层,再上一层是会话层,最后是最外层(服务器和客户端)。我用一张图来大致表达一下它们之间的关系。
安居客十分到家咯
以下是该框架所有的类名称:
.在这里插入图片描述

双工通信三要素

所谓双工,就是“双向通信工作”模式。
在C/S网络编程模式下,服务器与一个客户端进行双向通信时,必须拥有以下三要素:

  • Socket类的对象,即,通信端口封装类。由它才能创建下面的通信信道,并在结束通信时,关闭网络连接;
  • DataInputStream类的对象。接收来自“对端”信息的输入通信信道;
  • DataOutputStream类的对象。向“对端”发送消息的输出通信信道。

最底层——通信层的实现

通信层有以下功能:

  1. 建立通信信道;
  2. 提供发送,接收信息和关闭连接的方法;
  3. 检查并发现对端异常掉线,并通知上一层处理。

通信层作为最底层,它是客户端和服务器建立联系的枢纽,是共用的一套代码,是能同时给服务器会话层和客户端会话层提供方法。

我们先看Communication类的线程代码片段:
在这里插入图片描述

这个线程不停的运行,而且通过第40行(message = this.dis.readUTF())不间断的侦听对端发送的消息。通过Boolean类型的goon判断何时停止线程的运行,并且当对端异常掉线时异常捕获块会判断goon的值,若为true,则说明时对端异常掉线,此时会执行一个抽象类方法peerAbnormalDrop(),交给上一层(ServerConversation 和 ClientConversation)具体处理异常掉线的情况。

向对端发送信息的方法:
在这里插入图片描述

下面是Communication类的完整代码:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public  abstract class Communication implements Runnable{
	protected Socket socket;
	protected String ip;
	protected DataInputStream dis;
	protected DataOutputStream dos;
	protected volatile boolean goon;
	
	Communication(Socket socket) throws IOException {
		this.socket = socket;
		this.ip = this.socket.getInetAddress().getHostAddress();
		this.dis = new DataInputStream(this.socket.getInputStream());
		this.dos = new DataOutputStream(this.socket.getOutputStream());
		
		this.goon = true;
		new Thread(this).start();
	}
	
	void send(NetMessage message) {
		try {
			this.dos.writeUTF(NetMessage.gson.toJson(message));
		} catch (IOException e) {
			//向对端发消息失败,意味着对端已关闭通信!
			//关闭网络连接
			close();
		}
	}
	
	public abstract void dealNetMessage(NetMessage netMessage);
	public abstract void peerAbnormalDrop();

	@Override
	public void run() {
		String message = "";
		while (this.goon) {
			try {
				message = this.dis.readUTF();
				NetMessage netMessage = 
						NetMessage.gson.fromJson(message, NetMessage.class);
				dealNetMessage(netMessage);
			} catch (IOException e) {
				if (this.goon == true) {
					//goon为true,意味着对端异常掉线!
					//调用异常掉线处理。
					this.goon = false;
					peerAbnormalDrop();
				} 
				//若goon为false,意味着正常正常下线,
				//则什么都不用做。
			}
		}
		close();
	}
	
	protected void close() {
		this.goon = false;
		try {
			if (this.dis != null) {
				this.dis.close();
			}	
		} catch (IOException e) {
		} finally {
			this.dis = null;
		}
		
		try {
			if (this.dos != null) {
				this.dos.close();
			}	
		} catch (IOException e) {
		} finally {
			this.dos = null;
		}
		try {
			if (this.socket != null && !this.socket.isClosed()) {
				this.socket.close();
			}	
		} catch (IOException e) {
		} finally {
			this.socket = null;
		}
	}
	
}

网络信息的规范化

客户端与客户端不仅要进行文字,图片,音频等信息的互相发送,客户端与服务器端还要进行“命令式”操作,比如,客户端下线,就要给服务器发送一个消息,告诉它该客户端要下线,进而做出一系列有关下线的操作。但这条消息应该与其他的聊天消息区别开来,即,把“会话内容”和“网络命令”严格区分开来!

为了表示“网络命令”的方便,我们使用Enum(枚举):

public enum ENetCommand {
	OUT_OF_ROOM,
	ID,
	OFFLINE,
	
	TO_ONE,
	TO_OTHER,
	TO_SP_OTHER,
	
	FORCEDOWN,
	

上面的各种命令都是自定义的,代表了不同的命令,例如,TO_ONE(私聊),OFFLINE(下线)等。

现在讲讲NetMessage类,该类的对象生成服务器端和客户端要发送的信息。在发送和接收时,网络上传输的是本类对象形成的字符串,在发送前和接收后,应该转换为本类对象。(由于本类是工具的内部核心类,严禁包外接触,所以修饰符是“包修饰符”,即,无修饰。

下面是NetMessage类的完整代码:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class NetMessage {
	public static final Gson gson = new GsonBuilder().create();
	private ENetCommand command;
	private String action;
	private String message;
	
	public NetMessage() {
	}

	String getAction() {
		return action;
	}

	NetMessage setAction(String action) {
		this.action = action;
		return this;
	}

	ENetCommand getCommand() {
		return command;
	}

	NetMessage setCommand(ENetCommand command) {
		this.command = command;
		return this;
	}

	String getMessage() {
		return message;
	}

	NetMessage setMessage(String message) {
		this.message = message;
		return this;
	}
	
	
}

我们会看到该类定义了三个成员,command(ENetcommand类型,代表命令),action(String类型,这里不解释,以后会有用处),message(String类型,代表文字消息)。

注意NetMessage类中的这句代码public static final Gson gson = new GsonBuilder().create(),有一个Gson的类,该类的作用是实现对象和json字符串之间的转换,需要用到gson.jar。

在这里插入图片描述
上图代码就解释了Gson的作用:
在这里插入图片描述
将网络命令语句TO_ONE和文字消息“我爱你姑娘呦!”转换成一个键值对形式的字符串,相当于对发送的信息进行包装,分类的整合起来,以便传输。然而,说到传输,我们便要开始提到会话层了!

会话层是由通信层Communucation类派生出来的,我们分为服务器会话层ServerConversation类和客户端会话层ClientConversation类。会话层的作用是处理客户端与服务器端之间的各种联系,是其联系的桥梁。由于最外层的客户端和服务器端还没有写,我们先构建出会话层的空壳,在将来服务器端和客户端写好后,就可以完成会话层的一系列功能。

举报

相关推荐

0 条评论