闲来无事,就琢磨了一下socket;本节将实现一个简单的socket消息分发机制.功能比较简单,不喜勿喷.
现在成熟的消息分发有XMPP,MQTT等.分发协议参考JMS.
个人对MQTT比较熟悉.但是比较麻烦,用硬件设备实协议又要重新弄.所以就写个简单的搞下.
程序线程模型如下图所示:
主线程分别开启子线程监听端口(这里只考虑同时连接一个设备和手机):
public static Executor executor;
public static void main(String[] args) throws IOException {
executor = Executors.newFixedThreadPool(4);
executor.execute(new PhoneServer());
executor.execute(new DeviceServer());
while(true);
}
这里采用了线程池执行任务,没测性能,不知道具体情况.请自行测试或修改为创建线程.
当有socket连接到服务端时开启新的任务去维护输出流.当前线程则一直读取输入流数据.
public class PhoneServer implements Runnable {
ServerSocket phoneServer;
Socket phone;
public PhoneServer() throws IOException {
super();
phoneServer = new ServerSocket(10001);
}
public void run() {
phone = phoneServer.accept();
in = new BufferedReader(new InputStreamReader(
phone.getInputStream()));
out = new PrintWriter(phone.getOutputStream());
o = new PhoneOut(out);
MainThread.executor.execute(o);
.....
}
}
1.首先创建一个消息队列存放消息数据,这里为了方便就没有设计得更具体了.简单的搞一下
public class MessageEqueue extends Observable {
private List mPhoneMessage;
private List mDeviceMessage;
private static MessageEqueue instance;
public static MessageEqueue getInstance() {
if (instance == null) {
instance = new MessageEqueue();
}
return instance;
}
/**
*
*/
private MessageEqueue() {
mPhoneMessage = new ArrayList();
mDeviceMessage = new ArrayList();
}
......
}
创建两个list分别存放两个客户端发来的消息,如果想设计得更好请封装成消息对象.
2.观察者模式.让消息序列继承Observable类,当有新消息添加时,通知观察者更新输出数据.创建一个ObserverAction类封装更新信息:
public class ObserverAction {
public static final int ACTION_PHONE_UPDATE = 1;
public static final int ACTION_DEVICE_UPDATE = 2;
private int action;
private String msg ;
/**
* @param action
* @param msg
*/
public ObserverAction(int action, String msg) {
super();
this.action = action;
this.msg = msg;
}
/**
* @return the msg
*/
public String getMsg() {
return msg;
}
/**
* @param msg the msg to set
*/
public void setMsg(String msg) {
this.msg = msg;
}
/**
* @param action
*/
public ObserverAction(int action) {
super();
this.action = action;
}
/**
* @return the action
*/
public int getAction() {
return action;
}
/**
* @param action
* the action to set
*/
public void setAction(int action) {
this.action = action;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return "ObserverAction [action=" + action + ", msg=" + msg + "]";
}
}
添加新消息时,通过notifyObservers()方法通知观察者.
public synchronized void addDeviceMessage(String msg) {
mDeviceMessage.add(msg);
setChanged();
notifyObservers(new ObserverAction(ObserverAction.ACTION_DEVICE_UPDATE,
msg));
}
此处创建两个ACTION标记,来区分数据更新对象
public static final int ACTION_PHONE_UPDATE = 1;
public static final int ACTION_DEVICE_UPDATE = 2;
3.读取消息
创建一个死循环来不断的接收客户端的消息,收到消息后添加到消息队列中,由输出任务向另一个客户端输出数据.
o = new PhoneOut(out);
MainThread.executor.execute(o);
MessageEqueue.getInstance().addObserver(o);
while (true) {
try {
String str = in.readLine();
if (str != null) {
if (str.equals("end"))
break;
MessageEqueue.getInstance().addDeviceMessage(str);
}
} catch (IOException e) {
System.out.println(e.getMessage());
break;
}
}
4.输出消息.
前面提到创建一个新任务维护输出流,该任务没有消息时处于wait状态,当新消息到来时被唤醒.
public class PhoneOut implements Observer, Runnable {
private PrintWriter out;
private boolean isFinish = false;
private Object wait = new Object();
/**
* @param out
*/
public PhoneOut(PrintWriter out) {
super();
this.out = out;
}
public void run() {
while (!isFinish) {
try {
synchronized (wait) {
String msg = null;
while ((msg = MessageEqueue.getInstance()
.getPhoneLastMessage()) != null) {
out.println("device:" + msg);
out.flush();
}
wait.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("phone--end");
}
/**
* @return the isFinish
*/
public boolean isFinish() {
return isFinish;
}
/**
* @param isFinish
* the isFinish to set
*/
public void setFinish(boolean isFinish) {
this.isFinish = isFinish;
synchronized (wait) {
wait.notify();
}
}
public void update(Observable o, Object action) {
ObserverAction a = (ObserverAction) action;
if (a.getAction() == ObserverAction.ACTION_PHONE_UPDATE) {
// out.println("device:" + a.getMsg());
// out.flush();
synchronized (wait) {
wait.notify();
}
}
// if()
}
}
观察者更新时会调用update(Observable o, Object action)方法来更新观察者的状态.
synchronized (wait) {
String msg = null;
while ((msg = MessageEqueue.getInstance()
.getPhoneLastMessage()) != null) {
out.println("device:" + msg);
out.flush();
}
wait.wait();
}
当消息队列中的消息被发送完之后,任务会进入wait状态,直到下一次被新消息唤醒.
在监听任务中,为了重复监听,在run()方法中添加一个死循环来实现接受下一次的socket连接.
while (true) {
phone = phoneServer.accept();
System.out.println("PhoneServer.accept()");
in = new BufferedReader(new InputStreamReader(
phone.getInputStream()));
out = new PrintWriter(phone.getOutputStream());
o = new PhoneOut(out);
......
phone.close();
o.setFinish(true);
phone = null;
in = null;
out = null;
o = null;
}
在关闭socket之后要清除以前的对象引用,以及消息队列中的消息,避免消息错误.
附上源码:源码下载地址