基于WebSocket的Android与服务端通信
16lz
2021-01-23
之前写了一篇socket简单的聊天,前些天同学问我android的websocket是怎么玩的,捣鼓了一番决定用websocket也来写个例子看看,就有了本篇文章。
服务端采用的是:Servlet+websocket,因为自己javaEE也是半桶水哈
哈,所以就简单的写了下,先来看看效果图:
Android端使用的是Autobahn的包,支持Android 使用Websocket,下载地址:http://autobahn.ws/android/downloads/;
具体与服务器的连接方法WebSocketConnection. Connect()方法,通过WebSocketHandler进行与服务器连接通讯。里面的具体方法不再详述。
与不同的客户端进行通讯的思路为:
Step1:在连接成功的时候,向服务器发送自己的用户名,服务器做用户标记;
Step2: 发送消息,格式为“XX@XXX”,@前面表示将要发送的对象,“all”表示群发,@后面表示发送的消息。
具体实现为,android端代码:
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import de.tavendo.autobahn.WebSocketConnection; import de.tavendo.autobahn.WebSocketException; import de.tavendo.autobahn.WebSocketHandler; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String wsurl = "http://192.168.0.101:8080/websocketServer"; private static final String TAG = "MainActivity"; private WebSocketConnection mConnect = new WebSocketConnection(); private EditText mContent; private Button mSend; private TextView mText; private EditText mUserName; private EditText mToSb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindObject(); connect(); } /** * 绑定控件 */ private void bindObject() { mContent = (EditText) findViewById(R.id.et_content); mSend = (Button) findViewById(R.id.btn_send); mText = (TextView) findViewById(R.id.tv_test); mUserName = (EditText) findViewById(R.id.et_username); mToSb = (EditText) findViewById(R.id.et_to); mSend.setOnClickListener(this); } /** * websocket连接,接收服务器消息 */ private void connect() { Log.i(TAG, "ws connect...."); try { mConnect.connect(wsurl, new WebSocketHandler() { @Override public void onOpen() { Log.i(TAG, "Status:Connect to " + wsurl); sendUsername(); } @Override public void onTextMessage(String payload) { Log.i(TAG, payload); mText.setText(payload != null ? payload : ""); // mConnect.sendTextMessage("I am android client"); } @Override public void onClose(int code, String reason) { Log.i(TAG, "Connection lost.."); } }); } catch (WebSocketException e) { e.printStackTrace(); } } /** * 发送用户名给服务器 */ private void sendUsername() { String user = mUserName.getText().toString(); if (user != null && user.length() != 0) mConnect.sendTextMessage(user); else Toast.makeText(getApplicationContext(), "不能为空", Toast.LENGTH_SHORT).show(); } /** * 发送消息 * * @param msg */ private void sendMessage(String msg) { if (mConnect.isConnected()) { mConnect.sendTextMessage(msg); } else { Log.i(TAG, "no connection!!"); } } @Override protected void onDestroy() { super.onDestroy(); mConnect.disconnect(); } @Override public void onClick(View view) { if (view == mSend) { String content = mToSb.getText().toString() + "@" + mContent.getText().toString(); if (content != null && content.length() != 0) sendMessage(content); else Toast.makeText(getApplicationContext(), "内容不能为空", Toast.LENGTH_SHORT).show(); } } }
服务端主要是对于客户端连接的用户进行处理与标记,并且根据客户端的要求向不同对象转发消息,实现不同客户端之间的通讯。具体代码如下:
import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.HashMap; import java.util.concurrent.CopyOnWriteArraySet; /** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 */ @ServerEndpoint("/websocketServer") public class WebSocketTest { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //connect key为session的ID,value为此对象this private static final HashMap connect = new HashMap(); //userMap key为session的ID,value为用户名 private static final HashMap userMap = new HashMap(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //判断是否是第一次接收的消息 private boolean isfirst = true; private String username; /** * 连接建立成功调用的方法 * * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(Session session) { this.session = session; connect.put(session.getId(), this);//获取Session,存入Hashmap中 } /** * 连接关闭调用的方法 */ @OnClose public void onClose(Session session) { String usr = userMap.get(session.getId()); userMap.remove(session.getId()); connect.remove(session.getId()); System.out.println(usr + "退出!当前在线人数为" + connect.size()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 * @param session 可选的参数 */ @OnMessage public void onMessage(String message, Session session) { if (isfirst) { this.username = message; System.out.println("用户" + username + "上线,在线人数:" + connect.size()); userMap.put(session.getId(), username); isfirst = false; } else { String[] msg = message.split("@", 2);//以@为分隔符把字符串分为xxx和xxxxx两部分,msg[0]表示发送至的用户名,all则表示发给所有人 if (msg[0].equals("all")) { sendToAll(msg[1], session); } else { sendToUser(msg[0], msg[1], session); } } } /** * 发生错误时调用 * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { System.out.println("发生错误"); error.printStackTrace(); } /** * 给所有人发送消息 * * @param msg 发送的消息 * @param session */ private void sendToAll(String msg, Session session) { String who = ""; //群发消息 for (String key : connect.keySet()) { WebSocketTest client = (WebSocketTest) connect.get(key); if (key.equalsIgnoreCase(userMap.get(key))) { who = "自己对大家说 : "; } else { who = userMap.get(session.getId()) + "对大家说 :"; } synchronized (client) { try { client.session.getBasicRemote().sendText(who + msg); } catch (IOException e) { connect.remove(client); e.printStackTrace(); try { client.session.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } } /** * 发送给指定用户 * * @param user 用户名 * @param msg 发送的消息 * @param session */ private void sendToUser(String user, String msg, Session session) { boolean you = false;//标记是否找到发送的用户 for (String key : userMap.keySet()) { if (user.equalsIgnoreCase(userMap.get(key))) { WebSocketTest client = (WebSocketTest) connect.get(key); synchronized (client) { try { client.session.getBasicRemote().sendText(userMap.get(session.getId()) + "对你说:" + msg); } catch (IOException e) { connect.remove(client); try { client.session.close(); } catch (IOException e1) { e1.printStackTrace(); } } } you = true;//找到指定用户标记为true break; } } //you为true则在自己页面显示自己对xxx说xxxxx,否则显示系统:无此用户 if (you) { try { session.getBasicRemote().sendText("自己对" + user + "说:" + msg); } catch (IOException e) { e.printStackTrace(); } } else { try { session.getBasicRemote().sendText("系统:无此用户"); } catch (IOException e) { e.printStackTrace(); } } } }
完整演示代码
更多相关文章
- Android几种消息推送方案总结
- Android socket 编程 实现消息推送(二)
- [原]Android应用程序消息处理机制(Looper、Handler)分析
- Android消息推送完美解决方案全析
- Android客户端性能参数监控
- Android连接SQLServer详细教程(数据库+服务器+客户端),并在微软Azur