Android 使用Socket实现服务器与手机客户端的长连接七:定义消息体,区分是响应还是回复信息

一、分析:

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();
        }
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lovoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值