写博客 发Chat 打造自己的Android聊天软件(socket篇)

转自:https://blog.csdn.net/gusgao/article/details/52289813
其实打造属于自己的聊天软件很简单,今天我们讲学习如何简单的写一个群组聊天app,通过sockets实现。这不是唯一的方法,但却是最快和最简单的。最好和最有效的方式应该是使用推送通知(push notifications )而不是sockets。

翻译自http://www.androidhive.info/2014/10/android-building-group-chat-app-using-sockets-part-1/

github 项目地址
github

译者注:原文只给了代码很少有说明,译者会根据自己的情况适当加一些说明,比较复杂的章节将会单独写博客来说明:比如说websockets。

*译者注:重要说明:为防止各种不确定的因素请使用以下开发环境:
- Tomcat7
- javaee-api7*

在这篇文章中我们会做三个东西。第一个也是最重要的就是sockett server。socket server扮演着重要的作用:处理socket客户端连接,传递数据。第二个东西就是web app,你可以通过浏览器加入聊天。最后就是android app。最大的有点就是你可以在web – web, web – android 或者 android – android 进行聊天。

这个系列的文章有点长,把它分为两部分。第一部分就是web篇,第二部分安卓篇。

最终我们的app是这个样子的:

这里写图片描述

究竟App是如何在sockets上工作的?
首先你可以看维基百科或者百度百科。

首先,我们有一个正在运行的socket server,当安卓app或者web app连接的时候,server打开了一个在服务端与客户端的TCP连接,党有多个用户的时候,serever有能力处理多个连接。
当socket连接的时候会出发一系列的回调函数,例如 onOpen, onMessage, onExit,在客户端和服务端都会触发。
服务端与客户端用json进行交互。每一个json都有一个叫flag的字段来确认json的目的。下面的例子是当一个客户加入到对甲中所发送的json
{
“message”: ” joined conversation!”,
“flag”: “new”,
“sessionId”: “4”,
“name”: “Ravi Tamada”,
“onlineCount”: 6
}
1
2
3
4
5
6
7
当收到json信息的时候客户端就会解析。
开始服务端
首先下载三个jar包,放到WEB-INF lib下
google-collection

javeee-api7

json-org

创建一个叫JSONUtils的工具类,包含了众多创建json字符串的方法, 这额json在通信的时候被使用。
下面的代码,你看到每一个json都有一个flag节点,这个节点告诉客户端你的json字符串的目的,根据不同的目的采取不同的行动。

大体上flag有四种

self:这个json里包含了session信息,指定了一个特定的客户。当建立起sockets连接的时候,这回事客户端收到的第一个json。
new: 这个json在一个新客户加入socket server的时候向所有人广播。
message:这个包含了客户端所发送的消息,也会广播给每个人。
exit:当客户端退出连接的时候
package info.androidhive.webmobilegroupchat;

import org.json.JSONException;
import org.json.JSONObject;

public class JSONUtils {

// flags to identify the kind of json response on client side
private static final String FLAG_SELF = "self", FLAG_NEW = "new",
        FLAG_MESSAGE = "message", FLAG_EXIT = "exit";

public JSONUtils() {
}

/**
 * Json when client needs it's own session details
 * */
public String getClientDetailsJson(String sessionId, String message) {
    String json = null;

    try {
        JSONObject jObj = new JSONObject();
        jObj.put("flag", FLAG_SELF);
        jObj.put("sessionId", sessionId);
        jObj.put("message", message);

        json = jObj.toString();
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return json;
}

/**
 * Json to notify all the clients about new person joined
 * */
public String getNewClientJson(String sessionId, String name,
        String message, int onlineCount) {
    String json = null;

    try {
        JSONObject jObj = new JSONObject();
        jObj.put("flag", FLAG_NEW);
        jObj.put("name", name);
        jObj.put("sessionId", sessionId);
        jObj.put("message", message);
        jObj.put("onlineCount", onlineCount);

        json = jObj.toString();
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return json;
}

/**
 * Json when the client exits the socket connection
 * */
public String getClientExitJson(String sessionId, String name,
        String message, int onlineCount) {
    String json = null;

    try {
        JSONObject jObj = new JSONObject();
        jObj.put("flag", FLAG_EXIT);
        jObj.put("name", name);
        jObj.put("sessionId", sessionId);
        jObj.put("message", message);
        jObj.put("onlineCount", onlineCount);

        json = jObj.toString();
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return json;
}

/**
 * JSON when message needs to be sent to all the clients
 * */
public String getSendAllMessageJson(String sessionId, String fromName,
        String message) {
    String json = null;

    try {
        JSONObject jObj = new JSONObject();
        jObj.put("flag", FLAG_MESSAGE);
        jObj.put("sessionId", sessionId);
        jObj.put("name", fromName);
        jObj.put("message", message);

        json = jObj.toString();

    } catch (JSONException e) {
        e.printStackTrace();
    }

    return json;
}

}
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
创建SocketServer类
package info.androidhive.webmobilegroupchat;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.json.JSONException;
import org.json.JSONObject;

import com.google.common.collect.Maps;

@ServerEndpoint(“/chat”)
public class SocketServer {

// set to store all the live sessions
private static final Set<Session> sessions = Collections
        .synchronizedSet(new HashSet<Session>());

// Mapping between session and person name
private static final HashMap<String, String> nameSessionPair = new HashMap<String, String>();

private JSONUtils jsonUtils = new JSONUtils();

// Getting query params
public static Map<String, String> getQueryMap(String query) {
    Map<String, String> map = Maps.newHashMap();
    if (query != null) {
        String[] params = query.split("&");
        for (String param : params) {
            String[] nameval = param.split("=");
            map.put(nameval[0], nameval[1]);
        }
    }
    return map;
}

/**
 * Called when a socket connection opened
 * */
@OnOpen
public void onOpen(Session session) {

    System.out.println(session.getId() + " has opened a connection");

    Map<String, String> queryParams = getQueryMap(session.getQueryString());

    String name = "";

    if (queryParams.containsKey("name")) {

        // Getting client name via query param
        name = queryParams.get("name");
        try {
            name = URLDecoder.decode(name, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        // Mapping client name and session id
        nameSessionPair.put(session.getId(), name);
    }

    // Adding session to session list
    sessions.add(session);

    try {
        // Sending session id to the client that just connected
        session.getBasicRemote().sendText(
                jsonUtils.getClientDetailsJson(session.getId(),
                        "Your session details"));
    } catch (IOException e) {
        e.printStackTrace();
    }

    // Notifying all the clients about new person joined
    sendMessageToAll(session.getId(), name, " joined conversation!", true,
            false);

}

/**
 * method called when new message received from any client
 * 
 * @param message
 *            JSON message from client
 * */
@OnMessage
public void onMessage(String message, Session session) {

    System.out.println("Message from " + session.getId() + ": " + message);

    String msg = null;

    // Parsing the json and getting message
    try {
        JSONObject jObj = new JSONObject(message);
        msg = jObj.getString("message");
    } catch (JSONException e) {
        e.printStackTrace();
    }

    // Sending the message to all clients
    sendMessageToAll(session.getId(), nameSessionPair.get(session.getId()),
            msg, false, false);
}

/**
 * Method called when a connection is closed
 * */
@OnClose
public void onClose(Session session) {

    System.out.println("Session " + session.getId() + " has ended");

    // Getting the client name that exited
    String name = nameSessionPair.get(session.getId());

    // removing the session from sessions list
    sessions.remove(session);

    // Notifying all the clients about person exit
    sendMessageToAll(session.getId(), name, " left conversation!", false,
            true);

}

/**
 * Method to send message to all clients
 * 
 * @param sessionId
 * @param message
 *            message to be sent to clients
 * @param isNewClient
 *            flag to identify that message is about new person joined
 * @param isExit
 *            flag to identify that a person left the conversation
 * */
private void sendMessageToAll(String sessionId, String name,
        String message, boolean isNewClient, boolean isExit) {

    // Looping through all the sessions and sending the message individually
    for (Session s : sessions) {
        String json = null;

        // Checking if the message is about new client joined
        if (isNewClient) {
            json = jsonUtils.getNewClientJson(sessionId, name, message,
                    sessions.size());

        } else if (isExit) {
            // Checking if the person left the conversation
            json = jsonUtils.getClientExitJson(sessionId, name, message,
                    sessions.size());
        } else {
            // Normal chat conversation message
            json = jsonUtils
                    .getSendAllMessageJson(sessionId, name, message);
        }

        try {
            System.out.println("Sending Message To: " + sessionId + ", "
                    + json);

            s.getBasicRemote().sendText(json);
        } catch (IOException e) {
            System.out.println("error in sending. " + s.getId() + ", "
                    + e.getMessage());
            e.printStackTrace();
        }
    }
}

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
创建web app(Html Css Js)
style.css

body {
padding: 0;
margin: 0;
}

.body_container {
width: 1000px;
margin: 0 auto;
padding: 0;
}

.clear {
clear: both;
}

.green {
color: #8aaf0d;
}

header {

margin: 0 auto;
padding: 50px 0;
text-align: center;

}

header h1,#header p.online_count {

font-family: 'Open Sans', sans-serif;
font-weight: 300;

}

header p.online_count {

font-size: 18px;
display: none;

}

.box_shadow {
background: #f3f4f6;
border: 1px solid #e4e4e4;
-moz-box-shadow: 0px 0px 2px 1px #e5e5e5;
-webkit-box-shadow: 0px 0px 2px 1px #e5e5e5;
box-shadow: 0px 0px 2px 1px #e5e5e5;
}

prompt_name_container {

margin: 0 auto;
width: 350px;
text-align: center;

}

prompt_name_container p {

font-family: 'Open Sans', sans-serif;
font-weight: 300;
font-size: 24px;
color: #5e5e5e;

}

prompt_name_container #input_name {

border: 1px solid #dddddd;
padding: 10px;
width: 250px;
display: block;
margin: 0 auto;
outline: none;
font-family: 'Open Sans', sans-serif;

}

prompt_name_container #btn_join {

border: none;
width: 100px;
display: block;
outline: none;
font-family: 'Open Sans', sans-serif;
color: #fff;
background: #96be0e;
font-size: 18px;
padding: 5px 20px;
margin: 15px auto;
cursor: pointer;

}

message_container {

display: none;
width: 500px;
margin: 0 auto;
background: #fff;
padding: 15px 0 0 0;

}

messages {

margin: 0;
padding: 0;
height: 300px;
overflow: scroll;
overflow-x: hidden;

}

messages li {

list-style: none;
font-family: 'Open Sans', sans-serif;
font-size: 16px;
padding: 10px 20px;

}

messages li.new,#messages li.exit {

font-style: italic;
color: #bbbbbb;

}

messages li span.name {

color: #8aaf0d;

}

messages li span.red {

color: #e94e59;

}

input_message_container {

margin: 40px 20px 0 20px;

}

input_message {

background: #f0f0f0;
border: none;
font-size: 20px;
font-family: 'Open Sans', sans-serif;
outline: none;
padding: 10px;
float: left;
margin: 0;
width: 348px;

}

btn_send {

float: left;
margin: 0;
border: none;
color: #fff;
font-family: 'Open Sans', sans-serif;
background: #96be0e;
outline: none;
padding: 10px 20px;
font-size: 20px;
cursor: pointer;

}

btn_close {

margin: 0;
border: none;
color: #fff;
font-family: 'Open Sans', sans-serif;
background: #e94e59;
outline: none;
padding: 10px 20px;
font-size: 20px;
cursor: pointer;
width: 100%;
margin: 30px 0 0 0;

}
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
main.js

var sessionId = ”;

// name of the client
var name = ”;

// socket connection url and port
var socket_url = ‘192.168.0.102’;
var port = ‘8080’;

$(document).ready(function() {

$("#form_submit, #form_send_message").submit(function(e) {
    e.preventDefault();
    join();
});

});

var webSocket;

/**
* Connecting to socket
*/
function join() {
// Checking person name
if ( (‘#input_name’).val().trim().length <= 0) {          alert(‘Enter your name’);      } else {          name = (‘#input_name’).val().trim();

    $('#prompt_name_container').fadeOut(1000, function() {
        // opening socket connection
        openSocket();
    });
}

return false;

}

/**
* Will open the socket connection
*/
function openSocket() {
// Ensures only one connection is open at a time
if (webSocket !== undefined && webSocket.readyState !== WebSocket.CLOSED) {
return;
}

// Create a new instance of the websocket
webSocket = new WebSocket("ws://" + socket_url + ":" + port
        + "/WebMobileGroupChatServer/chat?name=" + name);

/**
 * Binds functions to the listeners for the websocket.
 */
webSocket.onopen = function(event) {
    $('#message_container').fadeIn();

    if (event.data === undefined)
        return;

};

webSocket.onmessage = function(event) {

    // parsing the json data
    parseMessage(event.data);
};

webSocket.onclose = function(event) {
    alert('Error! Connection is closed. Try connecting again.');
};

}

/**
* Sending the chat message to server
*/
function send() {
var message = $(‘#input_message’).val();

if (message.trim().length > 0) {
    sendMessageToServer('message', message);
} else {
    alert('Please enter message to send!');
}

}

/**
* Closing the socket connection
*/
function closeSocket() {
webSocket.close();

$('#message_container').fadeOut(600, function() {
    $('#prompt_name_container').fadeIn();
    // clearing the name and session id
    sessionId = '';
    name = '';

    // clear the ul li messages
    $('#messages').html('');
    $('p.online_count').hide();
});

}

/**
* Parsing the json message. The type of message is identified by ‘flag’ node
* value flag can be self, new, message, exit
*/
function parseMessage(message) {
var jObj = $.parseJSON(message);

// if the flag is 'self' message contains the session id
if (jObj.flag == 'self') {

    sessionId = jObj.sessionId;

} else if (jObj.flag == 'new') {
    // if the flag is 'new', a client joined the chat room
    var new_name = 'You';

    // number of people online
    var online_count = jObj.onlineCount;

    $('p.online_count').html(
            'Hello, <span class="green">' + name + '</span>. <b>'
                    + online_count + '</b> people online right now')
            .fadeIn();

    if (jObj.sessionId != sessionId) {
        new_name = jObj.name;
    }

    var li = '<li class="new"><span class="name">' + new_name + '</span> '
            + jObj.message + '</li>';
    $('#messages').append(li);

    $('#input_message').val('');

} else if (jObj.flag == 'message') {
    // if the json flag is 'message', it means somebody sent the chat
    // message

    var from_name = 'You';

    if (jObj.sessionId != sessionId) {
        from_name = jObj.name;
    }

    var li = '<li><span class="name">' + from_name + '</span> '
            + jObj.message + '</li>';

    // appending the chat message to list
    appendChatMessage(li);

    $('#input_message').val('');

} else if (jObj.flag == 'exit') {
    // if the json flag is 'exit', it means somebody left the chat room
    var li = '<li class="exit"><span class="name red">' + jObj.name
            + '</span> ' + jObj.message + '</li>';

    var online_count = jObj.onlineCount;

    $('p.online_count').html(
            'Hello, <span class="green">' + name + '</span>. <b>'
                    + online_count + '</b> people online right now');

    appendChatMessage(li);
}

}

/**
* Appending the chat message to list
*/
function appendChatMessage(li) {
$(‘#messages’).append(li);

// scrolling the list to bottom so that new message will be visible
$('#messages').scrollTop($('#messages').height());

}

/**
* Sending message to socket server message will be in json format
*/
function sendMessageToServer(flag, message) {
var json = ‘{“”}’;

// preparing json object
var myObject = new Object();
myObject.sessionId = sessionId;
myObject.message = message;
myObject.flag = flag;

// converting json object to json string
json = JSON.stringify(myObject);

// sending message to server
webSocket.send(json);

}
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
下载jquery-1.11.1.min

index.html



Android, WebSockets Chat App | AndroidHive
(www.androidhive.info)

猜你喜欢

转载自blog.csdn.net/My_stage/article/details/79862911