Android 使用Socket实现服务器与手机客户端的长连接七:定义消息体,区分是响应还是回复信息
2016-06-28 22:50
911 查看
一、分析:
1、示例图:如上图可以知道服务器给客户端会发送两条信息,一个是回复,另一个是推送信息,如何区分这些信息呢?就必须定义消息体协议*
———————————————————————
有需求者请加qq:136137465,非诚勿扰
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–
2、消息体协议:
1)请求部分:
{ "sequence": "9f4c696e-9ab5-46cf-959c-b1e2e35200d2", "type": "request", "action": "text" }
2)响应部分:
{ "sequence": "9f4c696e-9ab5-46cf-959c-b1e2e35200d2", "type": "response", "flag": "true" }
3)说明:
sequece : 标记 请求 和 响应,用来表明 响应 是 针对 哪次 请求的
type : 用来标记 是 请求 还是 响应
action : 请求发送方 的 发送类型,由具体请求 决定取值。
3、验证信息内容:
1)请求的 key-Value
key 类型 说明
type String 请求:request
sequence String 请求的序列号
action String 请求的行为:auth
sender String 发送者账号
token String 发送者token标志
2)请求的json 格式:
{ "sequence": "9f4c696e-9ab5-46cf-959c-b1e2e35200d2", "type": "request", "action": "auth", "sender":"xxxx", "token":"xxxx" } {"sequence":"1","type":"request","action":"auth","sender":"iphone1","token":"0dce6f76ac1a29d276c0c6dabe60519c"}
3)响应的格式:
成功 :
{ "sequence": "9f4c696e-9ab5-46cf-959c-b1e2e35200d2", "type": "response", "flag": "true", }
失败 :
{ "sequence": "9f4c696e-9ab5-46cf-959c-b1e2e35200d2", "type": "response", "flag": "false", "errorCode":"", "errorString":"" }
二、封装数据
1、创建接口public interface Request { String getData(); }
2、创建认证信息
public class AuthRequest implements Request { private Map<String, String> map = new HashMap<String, String>(); public AuthRequest(String sender, String token) { map.put("type", "request"); map.put("sequence", UUID.randomUUID().toString()); map.put("action", "auth"); map.put("sender", sender); map.put("token", token); } @Override public String getData() { return new Gson().toJson(map); } }
3、创建消息实体
public class TextRequest implements Request { private Map<String, String> map = new HashMap<String, String>(); public TextRequest(String sender, String token, String receiver, String content) { map.put("type", "request"); map.put("sequence", UUID.randomUUID().toString()); map.put("action", "text"); map.put("sender", sender); map.put("token", token); map.put("receiver", receiver); map.put("content", content); } @Override public String getData() { return new Gson().toJson(map); } }
三、更改ConnectorManager
添加方法:public void connect(AuthRequest auth) { connector = new Connector(); connector.setConnectorListener(this); connector.connect(); connector.auth(auth.getData()); } public void putRequest(Request request) { connector.putRequest(request.getData()); }
四、修改service
1、原来连接方法/** * 连接服务 */ @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { @Override public void run() { mConnManager = ConnectorManager.getInstance(); mConnManager.setConnectorListener(ConnService.this); mConnManager.connect("#A"); } }).start(); }
2、发送的string类型更改为request类型
@Override public void onCreate() { super.onCreate(); mConnManager = ConnectorManager.getInstance(); new Thread(new Runnable() { @Override public void run() { mConnManager.setConnectorListener(ConnService.this); AuthRequest request = null; if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) { request = new AuthRequest("B", "BToken"); } else { request = new AuthRequest("A", "AToken"); } mConnManager.connect(request); } }).start(); }
五、修改主界面发送信息方法
/** * 发送信息 * @param view */ public void clickMessage(View view){ if (!TextUtils.isEmpty(mEtContent.getText())) { String sender = "A"; String token = "AToken"; String receiver = "B"; //mConnectorManager.putRequest(mEtContent.getText().toString()); Request request = new TextRequest(sender, token, receiver, mEtContent.getText().toString()); mConnectorManager.putRequest(request); } }
六、修改服务器
1、原来只接收字符串信息public class Copy_2_of_TCPServer { public static void main(String[] args) { //final LinkedList<Socket> list = new LinkedList<Socket>(); final Map<String, Socket> map = new HashMap<String, Socket>(); int port = 10002; try { ServerSocket server = new ServerSocket(port); while (true) { // 获得客户端连接 // 阻塞式方法 System.out.println("准备阻塞..."); final Socket client = server.accept(); System.out.println("阻塞完成..."); // 添加到集合里 //list.add(client); new Thread(new Runnable() { @Override public void run() { try { // 输入流,为了获取客户端发送的数据 InputStream is = client.getInputStream(); // 得到输出流 OutputStream out = client.getOutputStream(); byte[] buffer = new byte[1024]; int len = -1; System.out.println("准备read..."); while ((len = is.read(buffer)) != -1) { String text = new String(buffer, 0, len); if (text.startsWith("#")) { map.put(text, client); // 回复认证信息 out.write("认证成功,over".getBytes()); }else { out.write("发送成功,over".getBytes()); String[] split = text.split(":");//发送信息时,用户名+“:” + content; String key = "#" + split[0];//split[0]表示用户名称 String content = split[1]; //发送信息给其它用户 Socket s = map.get(key); OutputStream outputStream = s.getOutputStream(); outputStream.write(content.getBytes()); } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } } catch (Exception e) { e.printStackTrace(); } } }
2、修改后接收request信息
public class TCPServer { public static void main(String[] args) { final Map<String, Socket> clientMap = new HashMap<String, Socket>(); int port = 10002; try { ServerSocket server = new ServerSocket(port); while (true) { // 获得客户端连接 // 阻塞式方法 System.out.println("准备阻塞..."); final Socket client = server.accept(); new Thread(new Runnable() { @Override public void run() { try { // 输入流,为了获取客户端发送的数据 InputStream is = client.getInputStream(); // 得到输出流 OutputStream out = client.getOutputStream(); byte[] buffer = new byte[1024]; int len = -1; System.out.println("准备read..."); while ((len = is.read(buffer)) != -1) { String text = new String(buffer, 0, len); TypeToken typeToken = new TypeToken<Map<String, String>>(){}; Map<String, String> msgMap = new Gson().fromJson(text, typeToken.getType()); String type = msgMap.get("type"); if ("request".equals(type)) { String action = msgMap.get("action"); if ("auth".equals(action)) { // 认证消息处理 String sender = msgMap.get("sender"); System.out.println(sender + "认证"); // 放到容器当中 clientMap.put(sender, client); } else if ("text".equals(action)) { // 文本消息 String sender = msgMap.get("sender"); String receiver = msgMap.get("receiver"); String content = msgMap.get("content"); Socket s = clientMap.get(receiver); if (s != null) { // 在线 OutputStream output = s.getOutputStream(); output.write((sender + content).getBytes()); } else { // 离线 TODO: } } } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } } catch (Exception e) { e.printStackTrace(); } } }
相关文章推荐
- java-模拟tomcat服务器
- Linux socket 初步
- 小心服务器内存居高不下的元凶--WebAPI服务
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题