[代码]servlet监听器中同时启动serversocket服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
package
com.safe.listener;
import
java.io.IOException;
import
java.net.ServerSocket;
import
javax.servlet.ServletContext;
import
javax.servlet.ServletContextEvent;
import
javax.servlet.ServletContextListener;
import
org.springframework.web.context.WebApplicationContext;
import
org.springframework.web.context.support.WebApplicationContextUtils;
import
tcp.thread.ServerThread;
import
tcp.util.TCPConstant;
import
com.safe.service.CenterService;
public
class
InitListener
implements
ServletContextListener {
ServerSocket server;
@Override
public
void
contextInitialized(ServletContextEvent event) {
System.out.println(
"web应用初始化:初始化的位置:启动ServerSocket的地方"
);
// 获取Spring容器以及service层对象
ServletContext servletContext = event.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
for
(
int
i =
0
; i < ctx.getBeanDefinitionNames().length; i++) {
System.out.println(ctx.getBeanDefinitionNames()[i]);
}
CenterService service = (CenterService) ctx
.getBean(
"centerServiceImpl"
);
// 启动serverSocket
try
{
server =
new
ServerSocket(TCPConstant.SERVER_PORT);
new
Thread(
new
ServerThread(server, service)).start();
System.out.println(
"一个TCPThreadForServer 的run执行完毕"
);
}
catch
(IOException e) {
System.out.println(
"初始化serverSocket 报错"
);
e.printStackTrace();
}
}
@Override
public
void
contextDestroyed(ServletContextEvent sce) {
System.out.println(
"web应用销毁 "
);
try
{
if
(
null
!= server) {
System.out.println(
"关闭ServerSocket"
);
server.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
|
2. [代码]serversocket线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
package
tcp.thread;
import
java.io.IOException;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.util.Hashtable;
import
java.util.Map;
import
java.util.concurrent.ConcurrentLinkedQueue;
import
org.apache.log4j.Logger;
import
tcp.framer.Frame;
import
com.safe.service.CenterService;
/**
* 每个套接字ServerSocket为一个线程,不然tomcat会阻塞等待socket客户端连接
*
* @author yh
*
*/
public
class
ServerThread
implements
Runnable {
private
static
Logger logger = Logger.getLogger(HandingClientThread.
class
);
public
static
final
Map<String, ConcurrentLinkedQueue<Frame>> queueMap =
new
Hashtable<String, ConcurrentLinkedQueue<Frame>>();
private
ServerSocket server;
private
CenterService service;
public
ServerThread() {
super
();
}
public
ServerThread(ServerSocket server, CenterService service) {
super
();
this
.server = server;
this
.service = service;
}
// public void closeServer() throws IOException {
// if (null != server) {
// System.out.println("closeServer():关闭server");
// server.close();
// }
// }
@Override
public
void
run() {
Socket client =
null
;
try
{
while
(!server.isClosed()) {
logger.info(
"serverthread.run():服务器开启,等待客户端访问....."
);
client = server.accept();
System.out.println(
"为什么这次debug要点两次才能直接跑过去"
);
logger.info(
"添加新的客户端socket:"
+ client + client.getInetAddress().getHostAddress() +
":"
+ client.getPort());
new
Thread(
new
HandingClientThread(client, service),
"HandingClientThread"
).start();
}
}
catch
(IOException e) {
logger.info(
"服务器启动失败!"
);
e.printStackTrace();
}
finally
{
try
{
if
(client !=
null
) {
client.close();
}
if
(server !=
null
) {
server.close();
logger.info(
"服务器关闭!"
);
}
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
}
|
3. [代码]为每一个客户端处理请求或发送
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
package
tcp.thread;
import
java.io.IOException;
import
java.net.Socket;
import
java.net.SocketException;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.concurrent.ConcurrentLinkedQueue;
import
org.apache.log4j.Logger;
import
tcp.coder.MsgCoder;
import
tcp.framer.Frame;
import
tcp.framer.LengthFramer;
import
tcp.msg.M_p_AlarmStatus;
import
tcp.msg.M_p_Pant;
import
tcp.msg.M_p_PeopleInfo;
import
tcp.msg.M_q_GetPeopleInfo;
import
tcp.msg.M_q_HandingAlarm;
import
tcp.msg.M_q_Pant;
import
tcp.msg.PoliceTask;
import
tcp.thread.son.WriteThread;
import
tcp.util.MsgUtil;
import
tcp.util.TCPConstant;
import
com.safe.model.Police;
import
com.safe.model.User;
import
com.safe.service.CenterService;
import
com.safe.util.ConstantUtil;
import
com.safe.util.DateUtil;
/**
* 每个访客一个线程
*
* @author yh
*
*/
// @Component
public
class
HandingClientThread
implements
Runnable {
private
static
Logger logger = Logger.getLogger(HandingClientThread.
class
);
private
Socket client;
private
CenterService service;
public
HandingClientThread() {
super
();
}
public
HandingClientThread(Socket client, CenterService service) {
super
();
this
.client = client;
this
.service = service;
}
public
Socket getClient() {
return
client;
}
public
void
setClient(Socket client) {
this
.client = client;
}
@Override
public
void
run() {
/** 添加发送队列到全局 */
String outListKey = client.getInetAddress().getHostAddress() +
":"
+ client.getPort();
ConcurrentLinkedQueue<Frame> writeQueue =
new
ConcurrentLinkedQueue<Frame>();
ServerThread.queueMap.put(outListKey, writeQueue);
logger.info(
"TCP服务端clientTread:有一个客户端socket连接到服务端:ServerThread.queueMap.size():"
+ ServerThread.queueMap.size());
// 成帧器 需要传给每个线程用来读取或写入帧
LengthFramer framer =
null
;
try
{
client.setKeepAlive(
true
);
client.setSoTimeout(
60
*
1000
);
// 这个方法表示
// 超时就报异常并断开读取连接,但是还可以向客户端发送.如有异常在读取位置抛出
framer =
new
LengthFramer(client,
"【服务端】"
);
}
catch
(SocketException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
logger.info(
"线程WriteThread启动"
);
new
Thread(
new
WriteThread(framer, writeQueue, service, client),
"WriteThread"
).start();
/*** 接受消息 并将响应结果放入写出队列 */
try
{
while
(
true
) {
Frame reqFrame;
reqFrame = framer.nextFrame();
Frame rspFrame =
null
;
int
msgType = reqFrame.getMsgType();
switch
(msgType) {
/** 一 收到心跳 */
case
TCPConstant.MSGTYPE_Q_PANT:
M_q_Pant m_q_Pant =
new
MsgCoder<M_q_Pant>().readFrame(reqFrame, M_q_Pant.
class
);
System.out.println(
"【服务端】<AC 心跳请求:"
+ m_q_Pant);
// 响应心跳
M_p_Pant p_Pant =
new
M_p_Pant();
rspFrame =
new
MsgCoder<M_p_Pant>().readMsg(p_Pant);
break
;
/** 二 获取人物信息请求 */
case
TCPConstant.MSGTYPE_Q_PEOPLEINFO:
M_q_GetPeopleInfo q_GetPeopleMsg =
new
MsgCoder<M_q_GetPeopleInfo>().readFrame(reqFrame,
M_q_GetPeopleInfo.
class
);
System.out.println(
"【服务端】<AC 查人请求:"
+ q_GetPeopleMsg);
byte
peopleType = q_GetPeopleMsg.getType();
if
(TCPConstant.PEOPLETYPE_POLICE == peopleType) {
// 警员
Police police = service.getPoliceByPoliceNo(q_GetPeopleMsg.getID().trim());
String birthdayStr = DateUtil.fmtDateToStr(police.getDetails().getBirthday(),
"yyyy-MM-dd"
);
rspFrame =
new
MsgCoder<M_p_PeopleInfo>().readMsg(
new
M_p_PeopleInfo(police.getPoliceNo(), peopleType, police.getDetails().getName(),
birthdayStr, police.getDetails().getTel(), police.getDetails().getAddress(),
police.getDetails().getShenFenId(), police.getDetails().getPhoto()));
}
else
if
(TCPConstant.PEOPLETYPE_USER == peopleType) {
// 用户
User user = service.getUserByLoginName(q_GetPeopleMsg.getID().trim());
String birthdayStr = DateUtil.fmtDateToStr(user.getDetails().getBirthday(),
"yyyy-MM-dd"
);
rspFrame =
new
MsgCoder<M_p_PeopleInfo>().readMsg(
new
M_p_PeopleInfo(user.getLoginName(), peopleType, user.getDetails().getName(),
birthdayStr, user.getDetails().getTel(), user.getDetails().getAddress(),
user.getDetails().getShenFenId(), user.getDetails().getPhoto()));
}
break
;
/** 三 处理报警请求(派警或者标记假警等) */
case
TCPConstant.MSGTYPE_Q_HANDINGALARM:
// 解析请求消息
M_q_HandingAlarm q_handingMsg =
new
MsgCoder<M_q_HandingAlarm>().readFrame(reqFrame,
M_q_HandingAlarm.
class
);
System.out.println(
"【服务端】《AC 处理报警请求:"
+ q_handingMsg);
// 操作派警
int
alarmId = q_handingMsg.getEventID();
byte
type = q_handingMsg.getType();
if
(type == ConstantUtil.ALARM_TYPE_TRUE) {
// 真警则派发任务
String taskContent = q_handingMsg.getTaskInfo();
// 派发任务
List<PoliceTask> policeTasks = q_handingMsg.getTask();
List<String> policeNos =
new
ArrayList<String>();
for
(PoliceTask policeTask : policeTasks) {
policeNos.add(policeTask.getPoliceID());
}
// service.sendTaskAndNotice(alarmId, policeNos,
// taskContent);// TODO 避免报别名不存在错误 暂时注释
}
else
{
// 不是真警 则修改对应类型 1假警 2重复报警
service.updateAlarmType(alarmId, type);
}
// 发送处理报警的响应消息()这个应该由警员提交任务时触发?并在提交任务的action中启动新线程连接对方再发送
// AlarmInfo alarmInfo=service.getAlarmById(alarmId);
// TODO 假数据
M_p_AlarmStatus msg =
new
M_p_AlarmStatus(alarmId, (
byte
)
1
);
Frame pMsgframe =
new
MsgCoder<M_p_AlarmStatus>().readMsg(msg);
// 添加到写出队列(所有)
MsgUtil.addFrametoAllQueueMap(pMsgframe);
break
;
default
:
logger.warn(
"AcceptRequestThread 未知的请求!~"
);
break
;
}
if
(rspFrame !=
null
) {
writeQueue.add(rspFrame);
}
}
}
catch
(IOException e) {
logger.error(
"服务端 读取失败,结束读取线程"
, e);
}
finally
{
ServerThread.queueMap.remove(client.getInetAddress().getHostAddress() +
":"
+ client.getPort());
try
{
client.shutdownInput();
client.shutdownOutput();
client.close();
logger.error(
"关闭客户端连接"
);
}
catch
(IOException e1) {
e1.printStackTrace();
}
}
}
}
|
4. [代码]循环写出到输出流线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
package
tcp.thread.son;
import
java.io.IOException;
import
java.net.Socket;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.concurrent.ConcurrentLinkedQueue;
import
org.apache.log4j.Logger;
import
com.safe.model.Police;
import
com.safe.model.User;
import
com.safe.service.CenterService;
import
tcp.coder.MsgCoder;
import
tcp.framer.Frame;
import
tcp.framer.LengthFramer;
import
tcp.msg.M_p_Alarm;
import
tcp.msg.M_p_PoliceCoordFlow;
import
tcp.msg.M_p_UserCoordFlow;
import
tcp.msg.PoliceCoord;
import
tcp.msg.UserCoord;
import
tcp.thread.ServerThread;
import
tcp.util.MyListUtil;
import
tcp.util.TCPConstant;
/**
* 位置流
*
* @author sh
*
*/
public
class
WriteThread
implements
Runnable {
private
static
Logger logger = Logger.getLogger(WriteThread.
class
);
private
LengthFramer framer;
private
ConcurrentLinkedQueue<Frame> writeQueue;
// 当前连接的写出队列
private
CenterService service;
private
Socket client;
public
WriteThread(LengthFramer framer,
ConcurrentLinkedQueue<Frame> writeQueue, CenterService service,
Socket client) {
super
();
this
.framer = framer;
this
.service = service;
this
.writeQueue = writeQueue;
this
.client = client;
}
@Override
public
void
run() {
logger.info(
"进入线程WriteThread"
);
long
lastTime_onlinePolice = System.currentTimeMillis();
// 上次发送时间 在线警员
long
lastTime_hotPolice = System.currentTimeMillis();
// 上次发送时间 忙碌警员
long
lastTime_aroundPolice = System.currentTimeMillis();
// 上次发送时间 事发周围警员
long
lastTime_hotUser = System.currentTimeMillis();
// 上次发送时间 报警人
long
lastTime_alarm = System.currentTimeMillis();
// 上次发送时间 报警人
try
{
while
(
true
) {
/** 发送输出队列中的帧 */
Frame frame = writeQueue.poll();
if
(frame !=
null
) {
framer.outFrame(frame);
}
/** 位置流 */
// 所有在线警员坐标流
if
(System.currentTimeMillis() - lastTime_onlinePolice > TCPConstant.INTERVAL_ONLINEPOLICE *
1000
) {
List<M_p_PoliceCoordFlow> policeCoordFlowMsgList = getPoliceCoordFlowMsgsByPoliceList(
service.getOnlinePoliceList(),
TCPConstant.MAXCOUNT_POLICECOORDS);
for
(M_p_PoliceCoordFlow policeCoordFlow : policeCoordFlowMsgList) {
Frame policeCoord_frame =
new
MsgCoder<M_p_PoliceCoordFlow>()
.readMsg(policeCoordFlow);
framer.outFrame(policeCoord_frame);
}
lastTime_onlinePolice = System.currentTimeMillis();
}
// 忙碌警员 坐标流
if
(System.currentTimeMillis() - lastTime_hotPolice > TCPConstant.INTERVAL_HOTPOLICE *
1000
) {
List<M_p_PoliceCoordFlow> policeCoordFlowMsgList = getPoliceCoordFlowMsgsByPoliceList(
service.getHotPoliceList(),
TCPConstant.MAXCOUNT_POLICECOORDS);
for
(M_p_PoliceCoordFlow policeCoordFlow : policeCoordFlowMsgList) {
Frame policeCoord_frame =
new
MsgCoder<M_p_PoliceCoordFlow>()
.readMsg(policeCoordFlow);
framer.outFrame(policeCoord_frame);
}
lastTime_hotPolice = System.currentTimeMillis();
}
// 事发周围警员 坐标流
if
(System.currentTimeMillis() - lastTime_aroundPolice > TCPConstant.INTERVAL_AROUNDPOLICE *
1000
) {
List<M_p_PoliceCoordFlow> policeCoordFlowMsgList = getPoliceCoordFlowMsgsByPoliceList(
service.getAllAroundPoliceList(),
TCPConstant.MAXCOUNT_POLICECOORDS);
for
(M_p_PoliceCoordFlow policeCoordFlow : policeCoordFlowMsgList) {
Frame policeCoord_frame =
new
MsgCoder<M_p_PoliceCoordFlow>()
.readMsg(policeCoordFlow);
framer.outFrame(policeCoord_frame);
}
lastTime_aroundPolice = System.currentTimeMillis();
}
// 报警人坐标流
if
(System.currentTimeMillis() - lastTime_hotUser > TCPConstant.INTERVAL_HOTUSER *
1000
) {
List<M_p_UserCoordFlow> userCoordFlowMsgList = getUserCoordFlowMsgsByUserList(
service.getHotUserList(),
TCPConstant.MAXCOUNT_USERCOORDS);
for
(M_p_UserCoordFlow userCoordFlow : userCoordFlowMsgList) {
Frame userCoordframe =
new
MsgCoder<M_p_UserCoordFlow>()
.readMsg(userCoordFlow);
framer.outFrame(userCoordframe);
}
lastTime_hotUser = System.currentTimeMillis();
}
/** 临时测试发送报警 */
if
(System.currentTimeMillis() - lastTime_alarm >
20
*
1000
) {
M_p_Alarm amMsg =
new
M_p_Alarm(
99
,
"userID"
,
110.110110110
,
91.1911911
,
System.currentTimeMillis(),
"jspAdress"
);
Frame alarmFrame =
new
MsgCoder<M_p_Alarm>().readMsg(amMsg);
framer.outFrame(alarmFrame);
lastTime_alarm = System.currentTimeMillis();
}
}
}
catch
(IOException e) {
logger.error(
"服务端 写出失败,结束写出线程"
, e);
}
finally
{
ServerThread.queueMap.remove(client.getInetAddress()
.getHostAddress() +
":"
+ client.getPort());
try
{
client.shutdownInput();
client.shutdownOutput();
client.close();
}
catch
(IOException e1) {
e1.printStackTrace();
}
}
}
/**
* 通过警员集合和指定消息包容量 获得警员位置流消息集合
*
* @param policeList
* @param maxcountPolicecoords
* @return
*/
private
List<M_p_PoliceCoordFlow> getPoliceCoordFlowMsgsByPoliceList(
List<Police> policeList,
int
maxcountPolicecoords) {
List<M_p_PoliceCoordFlow> msgList =
new
ArrayList<M_p_PoliceCoordFlow>();
// 将处在报警状态的用户集合按照 单个分包消息的最大量分割为多个子集合并组成双层集合返回
List<List<Police>> bilayerPoliceList = MyListUtil.splitList(policeList,
maxcountPolicecoords);
/** 如果处在报警状态的用户数量超过一定值则分包发送 */
for
(List<Police> sonPoliceList : bilayerPoliceList) {
List<PoliceCoord> policeCoordList =
new
ArrayList<PoliceCoord>();
for
(Police police : sonPoliceList) {
int
alarmId =
0
;
if
(
null
!= police.getCurrTask()) {
System.out.println(
"PoliceCoordsThread,该警员有当前任务"
);
alarmId = police.getCurrTask().getAlarmInfo().getId();
}
PoliceCoord policeCoord =
new
PoliceCoord(police.getPoliceNo(),
alarmId, police.getCoord().getX(), police.getCoord()
.getY());
policeCoordList.add(policeCoord);
}
M_p_PoliceCoordFlow msg =
new
M_p_PoliceCoordFlow(
policeCoordList.size(), policeCoordList);
msgList.add(msg);
}
return
msgList;
}
/**
* 通过用户集合和指定消息包容量 获得用户位置流消息集合
*
* @param userList
* @param maxCountUsercoords
* @return
*/
private
List<M_p_UserCoordFlow> getUserCoordFlowMsgsByUserList(
List<User> userList,
int
maxCountUsercoords) {
List<M_p_UserCoordFlow> msgList =
new
ArrayList<M_p_UserCoordFlow>();
// 将处在报警状态的用户集合按照 单个分包消息的最大量分割为多个子集合并组成双层集合返回
List<List<User>> bilayerUserList = MyListUtil.splitList(userList,
maxCountUsercoords);
/** 如果处在报警状态的用户数量超过一定值则分包发送 */
for
(List<User> sonUserList : bilayerUserList) {
List<UserCoord> userCoordList =
new
ArrayList<UserCoord>();
for
(User user : sonUserList) {
UserCoord userCoord =
new
UserCoord(user.getLoginName(), user
.getCoord().getX(), user.getCoord().getY());
userCoordList.add(userCoord);
}
M_p_UserCoordFlow msg =
new
M_p_UserCoordFlow(userCoordList.size(),
userCoordList);
msgList.add(msg);
}
return
msgList;
}
}
|
5. [代码]协议消息工具类,添加消息到所有消息列表,以便群发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
tcp.util;
import
java.util.Iterator;
import
java.util.Map;
import
java.util.concurrent.ConcurrentLinkedQueue;
import
tcp.framer.Frame;
import
tcp.thread.ServerThread;
public
class
MsgUtil {
// 添加到写出队列(所有)
public
static
void
addFrametoAllQueueMap(Frame pMsgframe) {
Iterator<ConcurrentLinkedQueue<Frame>> values = ServerThread.queueMap.values()
.iterator();
while
(values.hasNext()) {
ConcurrentLinkedQueue<Frame> writeQueue = values.next();
writeQueue.offer(pMsgframe);
// 给所有的连接的队列加上这个帧数据
}
}
}
|
6. [代码]字节工具类,将基本类型转换为字节数组(大端),再以16进制字符串返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
package
tcp.util;
import
java.io.ByteArrayOutputStream;
import
java.io.DataOutputStream;
import
java.io.IOException;
import
java.nio.ByteBuffer;
import
java.util.Arrays;
public
class
MyByteUtil_DataStream {
// 返回大字节序的字节数组
public
static
byte
[] int2byteArray(
int
i)
throws
IOException {
ByteArrayOutputStream byteStream =
null
;
DataOutputStream out =
null
;
byte
[] bytes =
null
;
try
{
byteStream =
new
ByteArrayOutputStream();
out =
new
DataOutputStream(byteStream);
out.writeInt(i);
out.flush();
bytes = byteStream.toByteArray();
}
finally
{
byteStream.close();
out.close();
}
return
bytes;
}
// 返回大字节序的字节数组
public
static
byte
[] short2byteArray(
short
s)
throws
IOException {
ByteArrayOutputStream byteStream =
null
;
DataOutputStream out =
null
;
byte
[] bytes =
null
;
try
{
byteStream =
new
ByteArrayOutputStream();
out =
new
DataOutputStream(byteStream);
out.writeShort(s);
out.flush();
bytes = byteStream.toByteArray();
}
finally
{
byteStream.close();
out.close();
}
return
bytes;
}
// 返回大字节序的字节数组
public
static
byte
[] String2byteArray(String s)
throws
IOException {
ByteArrayOutputStream byteStream =
null
;
DataOutputStream out =
null
;
byte
[] bytes =
null
;
try
{
byteStream =
new
ByteArrayOutputStream();
out =
new
DataOutputStream(byteStream);
out.writeChars(s);
out.flush();
bytes = byteStream.toByteArray();
}
finally
{
byteStream.close();
out.close();
}
return
bytes;
}
// 字节数组转换为16进制数组并以字符串返回
public
static
String byteArrayToHex(
byte
[] bs) {
char
[] chars =
"0123456789ABCDEF"
.toCharArray();
StringBuilder sb =
new
StringBuilder(
""
);
int
bit;
for
(
int
i =
0
; i < bs.length; i++) {
bit = (bs[i] &
0x0f0
) >>
4
;
sb.append(chars[bit]);
bit = bs[i] &
0x0f
;
sb.append(chars[bit]);
sb.append(
' '
);
}
return
sb.toString().trim();
}
public
static
void
main(String[] args)
throws
IOException {
System.out.println(byteArrayToHex(String2byteArray(
""
)));
System.out.println(byteArrayToHex(String2byteArray(
" "
)));
System.out.println(Arrays.toString(int2byteArray(
1
)));
System.out.println(
"[]"
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream
.short2byteArray((
short
)
55
))
+
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream
.short2byteArray((
short
)
1234
))
+
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream
.int2byteArray(
1121
))
+
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream
.String2byteArray(
"sdasdsadasd"
)));
}
}
|
7. [代码]分割list 的工具类,将一个list按照指定大小分割为多个,返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package
tcp.util;
import
java.util.ArrayList;
import
java.util.List;
public
class
MyListUtil {
public
static
<T> List<List<T>> splitList(List<T> list,
int
pageSize) {
List<List<T>> listArray =
new
ArrayList<List<T>>();
ArrayList<T> al =
new
ArrayList<T>();
for
(T x : list) {
al.add(x);
if
(pageSize == al.size()) {
listArray.add(al);
al =
new
ArrayList<T>();
}
}
if
(
0
!= al.size())
listArray.add(al);
return
listArray;
}
}
|
8. [代码]编码解码器使用了泛型,不用为每种消息写一个编码器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
package
tcp.coder;
import
java.util.ArrayList;
import
java.util.List;
import
org.apache.log4j.Logger;
import
com.google.gson.Gson;
import
tcp.framer.Frame;
import
tcp.framer.LengthFramer;
import
tcp.msg.BaseMsg;
import
tcp.msg.M_p_Alarm;
import
tcp.msg.M_p_AlarmStatus;
import
tcp.msg.M_p_Pant;
import
tcp.msg.M_p_PeopleInfo;
import
tcp.msg.M_p_PoliceCoordFlow;
import
tcp.msg.M_p_RequestSupport;
import
tcp.msg.M_p_UserCoordFlow;
import
tcp.msg.M_q_GetPeopleInfo;
import
tcp.msg.M_q_HandingAlarm;
import
tcp.msg.M_q_Pant;
import
tcp.msg.PoliceTask;
import
tcp.util.TCPConstant;
public
class
MsgCoder<M
extends
BaseMsg> {
private
static
Logger logger = Logger.getLogger(LengthFramer.
class
);
/**
* 将消息解析为帧
*
* @param msg
* @return
*/
public
Frame readMsg(M msg) {
String msgJson =
null
;
int
msgType = getMsgTypeByMsgClass(msg);
short
length = TCPConstant.MSGHEAD_LENGTH;
if
(msgType != TCPConstant.MSGTYPE_Q_PANT && msgType !=
0
) {
// 如果不是心跳请求——唯一没有消息体的包
msgJson =
new
Gson().toJson(msg);
length = (
short
) (length + msgJson.length() *
2
);
// length = (short) (length +
// msgJson.getBytes(TCPConstant.NET_STRCODE).length - 2);//
// -2表示减去unicode码的BOM
// } catch (UnsupportedEncodingException e) {
// logger.error("将字符串转换为字节数组(为取得字节长度) 错误", e);
// e.printStackTrace();
}
Frame frame =
new
Frame(length, TCPConstant.CHECKCODE, msgType, msgJson);
return
frame;
};
/**
* 将帧解析为消息
*
* @param frame
* @return
*/
public
M readFrame(Frame frame, Class<M> c) {
String msgJson = frame.getMsgJson();
M m =
new
Gson().fromJson(msgJson, c);
return
m;
};
private
int
getMsgTypeByMsgClass(M msg) {
if
(msg
instanceof
M_q_Pant) {
return
TCPConstant.MSGTYPE_Q_PANT;
}
else
if
(msg
instanceof
M_p_Pant) {
return
TCPConstant.MSGTYPE_P_PANT;
}
else
if
(msg
instanceof
M_p_Alarm) {
return
TCPConstant.MSGTYPE_P_ALARM;
}
else
if
(msg
instanceof
M_p_UserCoordFlow) {
return
TCPConstant.MSGTYPE_P_USERCOORD;
}
else
if
(msg
instanceof
M_p_PoliceCoordFlow) {
return
TCPConstant.MSGTYPE_P_POLICECOORD;
}
else
if
(msg
instanceof
M_q_GetPeopleInfo) {
return
TCPConstant.MSGTYPE_Q_PEOPLEINFO;
}
else
if
(msg
instanceof
M_p_PeopleInfo) {
return
TCPConstant.MSGTYPE_P_PEOPLEINFO;
}
else
if
(msg
instanceof
M_q_HandingAlarm) {
return
TCPConstant.MSGTYPE_Q_HANDINGALARM;
}
else
if
(msg
instanceof
M_p_AlarmStatus) {
return
TCPConstant.MSGTYPE_P_HANDINGALARM;
}
else
if
(msg
instanceof
M_p_RequestSupport) {
return
TCPConstant.MSGTYPE_P_REQUESTSUPPORT;
}
else
{
System.out.println(
"msg类型错误"
);
}
return
0
;
}
public
static
void
main(String[] args) {
MsgCoder<M_q_HandingAlarm> coder1 =
new
MsgCoder<M_q_HandingAlarm>();
PoliceTask task =
new
PoliceTask(
""
);
List<PoliceTask> tasks =
new
ArrayList<PoliceTask>();
tasks.add(task);
M_q_HandingAlarm q_HandingMsg =
new
M_q_HandingAlarm(
1
, (
byte
)
1
,
1
,
""
, tasks);
int
i = coder1.getMsgTypeByMsgClass(q_HandingMsg);
System.out.println(i);
System.out.println(TCPConstant.MSGTYPE_Q_HANDINGALARM);
Frame q_HandingFrame = coder1.readMsg(q_HandingMsg);
System.out.println(q_HandingFrame);
M_q_HandingAlarm de_q_HandingMsg = coder1.readFrame(q_HandingFrame, M_q_HandingAlarm.
class
);
System.out.println(de_q_HandingMsg);
MsgCoder<M_q_Pant> coder2 =
new
MsgCoder<M_q_Pant>();
M_q_Pant q_PantMsg =
new
M_q_Pant();
int
j = coder2.getMsgTypeByMsgClass(q_PantMsg);
System.out.println(j);
System.out.println(TCPConstant.MSGTYPE_Q_PANT);
Frame q_PantMsgFrame = coder2.readMsg(q_PantMsg);
System.out.println(q_PantMsgFrame);
M_q_Pant de_q_PantMsg = coder2.readFrame(q_PantMsgFrame, M_q_Pant.
class
);
System.out.println(de_q_PantMsg);
}
}
|
9. [代码]帧的处理类,从输入流读取,和向输出流发送
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
package
tcp.framer;
import
java.io.DataInputStream;
import
java.io.DataOutputStream;
import
java.io.IOException;
import
java.net.Socket;
import
org.apache.log4j.Logger;
import
tcp.util.MyByteUtil_DataStream;
import
tcp.util.TCPConstant;
public
class
LengthFramer {
private
static
Logger logger = Logger.getLogger(LengthFramer.
class
);
private
Socket socket;
private
DataInputStream in;
// wrapper for data I/O
private
DataOutputStream out;
private
String shenFen;
// 构造器,获取帧消息源的输入流,并将其包裹在一个 DataInputStream 中。
public
LengthFramer(Socket socket, String shenFen)
throws
IOException {
this
.socket = socket;
this
.in =
new
DataInputStream(socket.getInputStream());
this
.out =
new
DataOutputStream(socket.getOutputStream());
this
.shenFen = shenFen;
}
public
Socket getSocket() {
return
socket;
}
/**
* 发送一帧
*
* @param frame
* @throws IOException
*/
public
void
outFrame(Frame frame)
throws
IOException {
short
length = frame.getLength();
if
(length > Short.MAX_VALUE) {
throw
new
IOException(
"message too long"
);
}
short
checkCode = frame.getCheckCode();
int
msgType = frame.getMsgType();
String msgJson = frame.getMsgJson();
logger.info(shenFen +
"[编码并发送outFrame():]"
+ frame);
logger.info(shenFen +
"[HexArray]"
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream.short2byteArray(length)) +
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream.short2byteArray(checkCode)) +
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream.int2byteArray(msgType)) +
" "
+ MyByteUtil_DataStream
.byteArrayToHex(MyByteUtil_DataStream.String2byteArray(msgJson ==
null
?
""
: msgJson)));
out.writeShort(length);
out.writeShort(checkCode);
out.writeInt(msgType);
// 输出消息数据
if
(msgJson !=
null
&& !
""
.equals(msgJson)) {
out.writeChars(msgJson);
}
out.flush();
}
/**
* 读入一帧
*
* @return
* @throws IOException
*/
public
Frame nextFrame()
throws
IOException {
Frame frame =
null
;
short
length = in.readShort();
short
checkcode = in.readShort();
int
msgType = in.readInt();
// 读取指定数量的字节的消息体
int
msgLen = length - TCPConstant.MSGHEAD_LENGTH;
String msgJson =
null
;
if
(msgLen !=
0
) {
byte
[] msgBytes =
new
byte
[msgLen];
in.readFully(msgBytes);
// readfully() 将阻塞等待,直到接收到足够的字节来填满指定的数组.
// // if
// exception, it's a framing error.
msgJson =
new
String(msgBytes, TCPConstant.NET_STRCODE);
}
frame =
new
Frame(length, checkcode, msgType, msgJson);
logger.info(shenFen +
"[读取并解码 nextFrame():]"
+ frame);
logger.info(shenFen +
"[HexByteArray]"
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream.short2byteArray(length)) +
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream.short2byteArray(checkcode)) +
" "
+ MyByteUtil_DataStream.byteArrayToHex(MyByteUtil_DataStream.int2byteArray(msgType)) +
" "
+ MyByteUtil_DataStream
.byteArrayToHex(MyByteUtil_DataStream.String2byteArray(msgJson ==
null
?
""
: msgJson)));
return
frame;
}
}
|