CSFrameWork通信建立
该层基于长连接模式,仅负责消息的发送和接收,不对任何消息和通信异常处理。具体的处理流程由基于该层Conversation层(会话层)负责。
一、通信信道的开启与关闭
- 通过Socket类的输入流和输出流建立数据输入流和输出流
public abstract class Communicate {
public Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
private volatile boolean goon;
public Communicate(Socket socket) {
try {
this.socket = socket;
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
}
}
}
上述代码,可以进一步优化。流的构建是较耗时的,我可以不予及时建立,先完成对客户端其他业务逻辑处理。将流建立抛给一个线程处理。优点是当有大量客户端连接服务器时,可以减少客户端响应时间。弊端是:并发是乱序执行的,当服务器向客户端发送消息时,不知数据流是否构建完毕。
内部线程类:
private class ThreadTask implements Runnable {
@Override
public void run() {
try {
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
goon = true;
} catch (IOException e) {
goon =false;
}
}
}
- 通信层关闭
public void closeChannel() {
goon = false;
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
dos = null;
}
}
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
dis = null;
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
socket = null;
}
}
}
二、消息的接收与发送
- 消息接收
- 消息目前仅限于字符集。采取BIO模式,开辟线程侦听对端消息。
public abstract class Communicate implements Runnable {
private volatile boolean goon;
@Override
public void run() {
while(goon) {
try {
String message = dis.readUTF();
dealMessage(new NetMessage(message));
} catch (IOException e) {
if (goon == true) {
dealPeerDown();
}
closeChannel();
}
}
closeChannel();
}
public abstract void dealPeerDown();
public abstract void dealMessage(NetMessage netMessage);
}
- 给出处理消息的抽象方法,由Conversation层实现。NetMessage协议类,对消息格式化处理。
String message = dis.readUTF();
dealMessage(new NetMessage(message));
-
该线程需要不断侦听对端消息,用goon标记类控制循环,当通信异常时,可以通过goon出出循环。但由于线程可视性问题,需要加上volatile修饰goon。
-
当通信异常时,可分两种情况:1、对端异常,2、本端异常。
本端异常通常是由主动调用closeChannel()方法,此时goon == false.对端异常,goon==true,可以通过if语句判断处理后,关闭通信。
public void run() {
while(goon) {
try {
String message = dis.readUTF();
dealMessage(new NetMessage(message));
} catch (IOException e) {
if (goon == true) {
dealPeerDown();
}
closeChannel();
}
}
closeChannel();
}
- 消息发送
用线程构建数据流时,在发送数据前,必须检验线程是否执行完毕。
private final Thread initThread;
public Communicate(Socket socket) {
this.socket = socket;
initThread = new Thread(new ThreadTask());
initThread.start();
}
public void sendMessage(NetMessage netMessage) {
try {
if (initThread.isAlive()) {
initThread.join();
}
dos.writeUTF(netMessage.toString());
} catch (IOException e) {
closeChannel();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
四、总结
该层完成基本数据打包发送、数据侦听,以及关闭通信功能,构建了稳定通信基础。接下来在此基础上扩展,完成对数据处理的Conversation类。