http://www.oschina.net/code/snippet_2507499_53892

来源:互联网 发布:吴昕开的淘宝店叫什么 编辑:程序博客网 时间:2024/06/10 04:34

 [代码]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 implementsServletContextListener {
     
    ServerSocket server;
 
    @Override
    publicvoid 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);
            newThread(new ServerThread(server, service)).start();
            System.out.println("一个TCPThreadForServer 的run执行完毕");
        }catch (IOException e) {
            System.out.println("初始化serverSocket 报错");
            e.printStackTrace();
        }
    }
 
    @Override
    publicvoid 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 implementsRunnable {
    privatestatic Logger logger = Logger.getLogger(HandingClientThread.class);
 
    publicstatic final Map<String, ConcurrentLinkedQueue<Frame>> queueMap = newHashtable<String, ConcurrentLinkedQueue<Frame>>();
 
    privateServerSocket server;
    privateCenterService service;
 
    publicServerThread() {
        super();
    }
 
    publicServerThread(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
    publicvoid 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());
                newThread(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 implementsRunnable {
    privatestatic Logger logger = Logger.getLogger(HandingClientThread.class);
 
    privateSocket client;
    privateCenterService service;
 
    publicHandingClientThread() {
        super();
    }
 
    publicHandingClientThread(Socket client, CenterService service) {
        super();
        this.client = client;
        this.service = service;
    }
 
    publicSocket getClient() {
        returnclient;
    }
 
    publicvoid setClient(Socket client) {
        this.client = client;
    }
 
    @Override
    publicvoid 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启动");
        newThread(new WriteThread(framer, writeQueue, service, client), "WriteThread").start();
 
        /*** 接受消息 并将响应结果放入写出队列 */
        try{
            while(true) {
                Frame reqFrame;
                reqFrame = framer.nextFrame();
                Frame rspFrame =null;
                intmsgType = reqFrame.getMsgType();
                switch(msgType) {
                /** 一 收到心跳 */
                caseTCPConstant.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;
                /** 二 获取人物信息请求 */
                caseTCPConstant.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);
                    bytepeopleType = 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(
                                newM_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(
                                newM_p_PeopleInfo(user.getLoginName(), peopleType, user.getDetails().getName(),
                                        birthdayStr, user.getDetails().getTel(), user.getDetails().getAddress(),
                                        user.getDetails().getShenFenId(), user.getDetails().getPhoto()));
 
                    }
                    break;
                /** 三 处理报警请求(派警或者标记假警等) */
                caseTCPConstant.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);
 
                    // 操作派警
                    intalarmId = q_handingMsg.getEventID();
                    bytetype = 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 implementsRunnable {
    privatestatic Logger logger = Logger.getLogger(WriteThread.class);
    privateLengthFramer framer;
    privateConcurrentLinkedQueue<Frame> writeQueue;// 当前连接的写出队列
    privateCenterService service;
    privateSocket client;
 
    publicWriteThread(LengthFramer framer,
            ConcurrentLinkedQueue<Frame> writeQueue, CenterService service,
            Socket client) {
        super();
        this.framer = framer;
        this.service = service;
        this.writeQueue = writeQueue;
        this.client = client;
    }
 
    @Override
    publicvoid run() {
        logger.info("进入线程WriteThread");
 
        longlastTime_onlinePolice = System.currentTimeMillis();// 上次发送时间 在线警员
        longlastTime_hotPolice = System.currentTimeMillis();// 上次发送时间 忙碌警员
        longlastTime_aroundPolice = System.currentTimeMillis();// 上次发送时间 事发周围警员
        longlastTime_hotUser = System.currentTimeMillis();// 上次发送时间 报警人
 
        longlastTime_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
     */
    privateList<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) {
                intalarmId = 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);
        }
        returnmsgList;
    }
 
    /**
     * 通过用户集合和指定消息包容量 获得用户位置流消息集合
     *
     * @param userList
     * @param maxCountUsercoords
     * @return
     */
    privateList<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);
        }
        returnmsgList;
    }
}

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 {
    // 添加到写出队列(所有)
    publicstatic  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 {
    // 返回大字节序的字节数组
    publicstatic byte[] int2byteArray(inti) 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();
        }
        returnbytes;
    }
 
    // 返回大字节序的字节数组
    publicstatic byte[] short2byteArray(shorts) 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();
        }
        returnbytes;
    }
 
    // 返回大字节序的字节数组
    publicstatic 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();
        }
        returnbytes;
    }
 
    // 字节数组转换为16进制数组并以字符串返回
    publicstatic String byteArrayToHex(byte[] bs) {
        char[] chars ="0123456789ABCDEF".toCharArray();
        StringBuilder sb =new StringBuilder("");
 
        intbit;
 
        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(' ');
        }
        returnsb.toString().trim();
 
    }
 
    publicstatic 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 {
    publicstatic <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);
 
        returnlistArray;
    }
}

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 extendsBaseMsg> {
    privatestatic Logger logger = Logger.getLogger(LengthFramer.class);
 
    /**
     * 将消息解析为帧
     *
     * @param msg
     * @return
     */
    publicFrame readMsg(M msg) {
        String msgJson =null;
        intmsgType = getMsgTypeByMsgClass(msg);
        shortlength = 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);
        returnframe;
    };
 
    /**
     * 将帧解析为消息
     *
     * @param frame
     * @return
     */
    publicM readFrame(Frame frame, Class<M> c) {
        String msgJson = frame.getMsgJson();
        M m =new Gson().fromJson(msgJson, c);
        returnm;
    };
 
    privateint getMsgTypeByMsgClass(M msg) {
        if(msg instanceofM_q_Pant) {
            returnTCPConstant.MSGTYPE_Q_PANT;
        }else if(msg instanceofM_p_Pant) {
            returnTCPConstant.MSGTYPE_P_PANT;
        }else if(msg instanceofM_p_Alarm) {
            returnTCPConstant.MSGTYPE_P_ALARM;
        }else if(msg instanceofM_p_UserCoordFlow) {
            returnTCPConstant.MSGTYPE_P_USERCOORD;
        }else if(msg instanceofM_p_PoliceCoordFlow) {
            returnTCPConstant.MSGTYPE_P_POLICECOORD;
        }else if(msg instanceofM_q_GetPeopleInfo) {
            returnTCPConstant.MSGTYPE_Q_PEOPLEINFO;
        }else if(msg instanceofM_p_PeopleInfo) {
            returnTCPConstant.MSGTYPE_P_PEOPLEINFO;
        }else if(msg instanceofM_q_HandingAlarm) {
            returnTCPConstant.MSGTYPE_Q_HANDINGALARM;
        }else if(msg instanceofM_p_AlarmStatus) {
            returnTCPConstant.MSGTYPE_P_HANDINGALARM;
        }else if(msg instanceofM_p_RequestSupport) {
            returnTCPConstant.MSGTYPE_P_REQUESTSUPPORT;
        }else {
            System.out.println("msg类型错误");
        }
 
        return0;
    }
 
    publicstatic 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);
        inti = 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();
        intj = 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 {
    privatestatic Logger logger = Logger.getLogger(LengthFramer.class);
 
    privateSocket socket;
    privateDataInputStream in; // wrapper for data I/O
    privateDataOutputStream out;
 
    privateString shenFen;
 
    // 构造器,获取帧消息源的输入流,并将其包裹在一个 DataInputStream 中。
    publicLengthFramer(Socket socket, String shenFen) throwsIOException {
        this.socket = socket;
        this.in =new DataInputStream(socket.getInputStream());
        this.out =new DataOutputStream(socket.getOutputStream());
        this.shenFen = shenFen;
    }
 
    publicSocket getSocket() {
        returnsocket;
    }
 
    /**
     * 发送一帧
     *
     * @param frame
     * @throws IOException
     */
    publicvoid outFrame(Frame frame)throws IOException {
 
        shortlength = frame.getLength();
        if(length > Short.MAX_VALUE) {
            thrownew IOException("message too long");
 
        }
 
        shortcheckCode = frame.getCheckCode();
        intmsgType = 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
     */
    publicFrame nextFrame() throwsIOException {
        Frame frame =null;
        shortlength = in.readShort();
        shortcheckcode = in.readShort();
        intmsgType = in.readInt();
        // 读取指定数量的字节的消息体
        intmsgLen = 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)));
 
        returnframe;
    }
 
}
0 0