Socket实现java服务端与AndroidApp端数据交互
在這里主要想實現服務端向App端推送消息,所以采用了Socket。
java端:
第一步:創建ServerSocketManager.java類,這個類是針對客戶端和App端的連接和斷開進行監聽,讀取并發送數據這幾個功能的封裝,具體代碼如下:
public class ServerSocketManager { //ServerSocketManager.java開始
private static ServerSocketManager manager;
?// 存儲客戶端ip-SocketChannel
?private static Map<String, SocketChannel> map;
?// 連接監聽
?private static SelectorLoop connectionBell;
?// 讀取監聽
?private static List<SelectorLoop> readBells;
?private ServerSocketChannel ssc;
?// 標識是否已經開啟讀取客戶端數據的線程
?public boolean isReadBellRunning = false;
?// 客戶端連接斷開監聽
?private List<OnClientListener> clientListeners;
?// 接收客戶端信息監聽
?private List<OnReceivedMessageListener> messageListeners;
?public void addOnClientListener(OnClientListener clientListener) {
??if (!this.clientListeners.contains(clientListener)) {
???this.clientListeners.add(clientListener);
??}
?}
?public void removeClientListener(OnClientListener clientListener) {
??this.clientListeners.remove(clientListener);
?}
?public void addOnReveicedMessageListener(
???OnReceivedMessageListener messageListener) {
??if (!this.messageListeners.contains(messageListener)) {
???this.messageListeners.add(messageListener);
??}
?}
?public void removeOnReveicedMessageListener(
???OnReceivedMessageListener messageListener) {
??this.messageListeners.remove(messageListener);
?}
?private ServerSocketManager() {
??map = new HashMap<String, SocketChannel>();
??clientListeners = new LinkedList<OnClientListener>();
??messageListeners = new LinkedList<ServerSocketManager.OnReceivedMessageListener>();
?}
?public synchronized static ServerSocketManager getInstance() {
??if (manager == null) {
???manager = new ServerSocketManager();
??}
??return manager;
?}
?public void startServer(String host, int port) throws IOException {
??System.out.println("-------ip-----" + host);
??readBells = new LinkedList<ServerSocketManager.SelectorLoop>();
??connectionBell = new SelectorLoop();
??// 開啟一個server channel來監聽
??ssc = ServerSocketChannel.open();
??// 開啟非阻塞模式
??ssc.configureBlocking(false);
??ServerSocket socket = ssc.socket();
??socket.bind(new InetSocketAddress(host, port));
??// 給鬧鐘規定好要監聽報告的事件,這個鬧鐘只監聽新連接事件.
??ssc.register(connectionBell.getSelector(), SelectionKey.OP_ACCEPT);
??new Thread(connectionBell).start();
?}
?public class SelectorLoop implements Runnable {
??private Selector selector;
??private ByteBuffer temp = ByteBuffer.allocate(1024);
??private boolean stop;
??private boolean using;
??public boolean isUsing() {
???return using;
??}
??public SelectorLoop() throws IOException {
???this.selector = Selector.open();
??}
??public Selector getSelector() {
???return this.selector;
??}
??public void stop() throws IOException {
???this.stop = true;
???if (this.selector.isOpen()) {
????this.selector.close();
????this.selector = null;
???}
??}
??@Override
??public void run() {
???using = true;
???while (!stop) {
????System.out.println("-----------");
????try {
?????// 阻塞,只有當至少一個注冊的事件發生的時候才會繼續.
?????if (this.selector.select() > 0) {
??????Set<SelectionKey> selectKeys = this.selector
????????.selectedKeys();
??????Iterator<SelectionKey> it = selectKeys.iterator();
??????while (it.hasNext()) {
???????SelectionKey key = it.next();
???????it.remove();
???????// 處理事件. 可以用多線程來處理.
???????this.dispatch(key);
??????}
?????}
????} catch (IOException e) {
?????e.printStackTrace();
????} catch (InterruptedException e) {
?????e.printStackTrace();
????} catch (Exception e) {
????}
???}
???stop = true;
??}
??public void dispatch(SelectionKey key) throws IOException,
????InterruptedException {
???System.out.println("-----dispatch----------");
???// 測試此鍵的通道是否已準備好接受新的套接字連接。
???if (key.isAcceptable()) {
????System.out.println("-----isAcceptable----------");
????// 這是一個connection accept事件, 并且這個事件是注冊在serversocketchannel上的.
????// 返回創建此鍵的通道
????ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
????// 接受一個連接.
????SocketChannel sc = ssc.accept();
????// 對新的連接的channel注冊read事件. 使用readBell鬧鐘.
????sc.configureBlocking(false);
????SelectorLoop readBell = new SelectorLoop();
????readBells.add(readBell);
????sc.register(readBell.getSelector(), SelectionKey.OP_READ);
????String host = ((InetSocketAddress) sc.getRemoteAddress())
??????.getHostString();
int port=((InetSocketAddress) sc.getRemoteAddress()).getPort();//部署在外網時,需要獲取隨機的端口
????host=host+":"+port;
????// 存放連接的socket
????map.put(host, sc);
????if (!clientListeners.isEmpty()) {
?????// 觸發連接監聽
?????for (OnClientListener cl : clientListeners) {
??????cl.onConnected(host);
?????}
????}
????// 如果讀取線程還沒有啟動,那就啟動一個讀取線程.
????// synchronized (ServerSocketManager.this) {
????// if (!ServerSocketManager.this.isReadBellRunning) {
????// ServerSocketManager.this.isReadBellRunning = true;
????new Thread(readBell).start();
????// }
????// }
???} else if (key.isReadable()) {
????// 這是一個read事件,并且這個事件是注冊在socketchannel上的.
????SocketChannel sc = (SocketChannel) key.channel();
????String host = ((InetSocketAddress) sc.getRemoteAddress())
??????.getHostString();
??? int port=((InetSocketAddress) sc.getRemoteAddress()).getPort();//部署在外網時,需要獲取隨機的端口
????host=host+":"+port;
????// 寫數據到buffer
????int count = sc.read(temp);
????System.out.println("-------count-------" + count);
????if (count < 0) {
?????map.remove(host);
?????stop();
?????if (!clientListeners.isEmpty()) {
??????for (OnClientListener cl : clientListeners) {
???????cl.onDisconnected(host);
??????}
?????}
?????// 客戶端已經斷開連接.
?????key.cancel();
?????sc.close();
?????return;
????}
????// 切換buffer到讀狀態,內部指針歸位.
????temp.flip();
????String msg = Charset.forName("UTF-8").decode(temp).toString();
????// 清空buffer
????temp.clear();
????if (msg != null && !"".equals(msg)
??????&& !messageListeners.isEmpty()) {
?????for (OnReceivedMessageListener rml : messageListeners) {
??????rml.onReceivedMessage(host, msg);
?????}
????}
???}
??}
?}
?public void stop() {
??try {
???// if (readBell != null) {
???// readBell.stop();
???// }
???if (connectionBell != null) {
????connectionBell.stop();
???}
???if (ssc != null && ssc.isOpen()) {
????ssc.close();
???}
??} catch (IOException e) {
???e.printStackTrace();
??}
?}
/**
? * 發送信息
? *
? * @param host
? * @param msg
? * @throws IOException
? */
?public int sendMessage(String host, byte[] msg) throws IOException {
??System.out.println("host====" + host);
??SocketChannel sc = map.get(host);
??int retnum = 0;
??if (sc == null) {
???// System.out.println("--------發送失敗,未找到對應的連接信息---------");
???return 0;
??}
??if (sc.isConnected()) {
???// echo back.
???sc.write(ByteBuffer.wrap(msg));
???retnum = 1;
??} else {
???System.out.println("---SocketChannel未開啟--");
???retnum = -1;
??}
??return retnum;
?}
?/**
? * 發送信息
? *
? * @param host
? * @param msg
? * @param charset
? * @throws IOException
? */
?public int sendMessage(String host, String msg, String charset)
???throws IOException {
??return sendMessage(host, msg.getBytes(charset));
?}
?/**
? * 發送信息 charset default utf-8
? *
? * @param host
? * @param msg
? * @throws IOException
? */
?public int sendMessage(String host, String msg) throws IOException {
??return sendMessage(host, msg.getBytes("UTF-8"));
?}
?/**
? * 監聽客戶端連接和斷開
? *
? * @author YJH
? *
? */
?public interface OnClientListener {
??/**
?? * 有客戶端連接時調用
?? *
?? * @param host
?? */
??void onConnected(String host);
??/**
?? * 有客戶端斷開連接時調用
?? *
?? * @param host
?? */
??void onDisconnected(String host);
?}
?/**
? * 監聽客戶端發送來的消息
? *
? * @author YJH
? *
? */
?public interface OnReceivedMessageListener {
??/**
?? * 接收到消息
?? *
?? * @param host
?? *??????????? 客戶端ip
?? * @param msg
?? *??????????? 客戶端信息
?? */
??void onReceivedMessage(String host, String msg);
?}
} //ServerSocketManager.java結束
第二步:把方法封裝完后,接下來,我們就可以在其它類里調用這些方法了,創建ServerSocketService.java類,代碼如下:
@Service??? //ServerSocketService.java開始
public class ServerSocketService {
?@Resource
?private FrameDao frameDao;
?public void setFrameDao(FrameDao frameDao) {
??this.frameDao = frameDao;
?}
?private ServerSocketManager manager;
?private OnClientListener clientListener = new OnClientListener() {
??@Override
??public void onDisconnected(String host) {
???System.out.println("斷開:" + host);
?? //斷開連接時要做的操作寫這里
??}
??@Override
??public void onConnected(String host) {
???System.out.println("接入:" + host);
? ?//連接上時要做的操作寫這里
??}
?};
?private OnReceivedMessageListener messageListener = new OnReceivedMessageListener() {
??@Override? ?//host是接入的ip,msg是接收到的信息
??public void onReceivedMessage(String host, String msg) {
???System.out.println("----msg--------" + msg);
???RequestData data = JSON.parseObject(msg,
?????new TypeReference<RequestData>() {???? //自定義的類:RequestData
?????});
???Map<String, String> datamap = data.getData();
???String lightid = datamap.get("lightid");
???String projectname = datamap.get("projectname");
???String mac=datamap.get("mac");
???int act = data.getAct();// 操作id,是App端發送過來的值
???System.out.println(act + "----act---");
???switch (act) {
???case 1:
??? //如果是操作標志是1的話進行的操作
????break;
???case 2:
??? //如果是操作標志是2的話進行的操作
????break;
???default:
????break;
???}
??}
?};
?{
??try {
???manager = ServerSocketManager.getInstance();
???manager.addOnClientListener(clientListener);
???manager.addOnReveicedMessageListener(messageListener);
???String ip = IP.getInstance().getAcceptIp();
???if (ip != null && !"".equals(ip)) {
????manager.startServer(ip, 9090);// ip是服務器的ip
????System.out.println("-------ServerSocketManager------");
???} else {
????System.out.println("-------讀取ip配置失敗------");
???}
??} catch (IOException e) {
???// TODO Auto-generated catch block
???e.printStackTrace();
??}
?}
?public String sendMessage(String projectid, String light) {
//推送的信息一般是JSON類型,轉換可以使用fastjson
//獲的要推送的信息frameInfo
???List<FrameInfo> frameInfo = frameDao.pushFrameInfo(
?????Integer.parseInt(projectid), lights[i]);
???try {
????int num = manager.sendMessage(frameInfo.get(0).getIp(),
??????JSON.toJSONString(frameInfo));
????if (num == 1) {
?????msg = "推送成功";
????} else if (num == 0) {
?????msg = "發送失敗,未找到對應的連接信息";
????} else {
?????msg = "Socket連接未開啟";
????}
???} catch (IOException e) {
????// TODO Auto-generated catch block
????e.printStackTrace();
???}
??}
??return msg;
?}
}? //ServerSocketService.java結束
第三步:創建RequestData.java類:
public class RequestData {
?private Integer act;//操作
?private Map<String, String> data;
?public Integer getAct() {
??return act;
?}
?public void setAct(Integer act) {
??this.act = act;
?}
?public Map<String, String> getData() {
??return data;
?}
?public void setData(Map<String, String> data) {
??this.data = data;
?}
?public RequestData() {
??super();
??// TODO Auto-generated constructor stub
?}
?public RequestData(Integer act, Map<String, String> data) {
??super();
??this.act = act;
??this.data = data;
?}
}
到此java服務器端完成,接下來android端
第一步:創建ClientManager.java類:
public class ClientManager {private static ClientManager manager;
private SocketChannel socketChannel;
private SelectorLoop readBell;
private OnConnectedListener connectedListener;
private OnReceivedMessageListener messageListener;
private ByteBuffer temp = ByteBuffer.allocate(1024);
public void setOnReceivedMessageListener(OnReceivedMessageListener messageListener) {
this.messageListener = messageListener;
}
public void setOnConnectedListener(OnConnectedListener connectedListener) {
this.connectedListener = connectedListener;
}
private ClientManager() {
}
public static ClientManager getInstance() {
if (manager == null) {
manager = new ClientManager();
}
return manager;
}
public void sendMessage(String msg, String charset) {
sendMessage(msg.getBytes(Charset.forName(charset)));
}
public void sendMessage(String msg) {
Log.e("aaa",msg+"--sendMessage---");
sendMessage(msg.getBytes(Charset.forName("UTF-8")));
}
public void sendMessage(final byte[] msg) {
new Thread() {
@Override
public void run() {
try {
if(socketChannel.isConnected()) {
socketChannel.write(ByteBuffer.wrap(msg));
}else{
Log.e("aaaa","-------連接已斷開------");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
public void start(final String host, final int port) {
new Thread() {
@Override
public void run() {
try {
readBell = new SelectorLoop();
// 連接遠程server
socketChannel = SocketChannel.open();
boolean isConnected;
while (true) {
try {
isConnected = socketChannel.connect(new InetSocketAddress(host, port));
break;
} catch (Exception e) {
Thread.sleep(1000);
}
}
socketChannel.configureBlocking(false);
SelectionKey key = socketChannel.register(readBell.getSelector(), SelectionKey.OP_READ);
if (isConnected) {
if (connectedListener != null) {
connectedListener.onConnected();
}
} else {
key.interestOps(SelectionKey.OP_CONNECT);
}
new Thread(readBell).start();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
class SelectorLoop implements Runnable {
private Selector selector;
private boolean stop;
public SelectorLoop() throws IOException {
this.selector = Selector.open();
}
public Selector getSelector() {
return this.selector;
}
public void stop() throws IOException {
this.stop = true;
if (this.selector.isOpen()) {
this.selector.close();
}
}
@Override
public void run() {
while (!stop) {
try {
if (this.selector.select() > 0) {
Log.e("aaaa", "--------有數據讀取------");
Set<SelectionKey> keys = this.selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
dispatchSelectionKey(key);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void dispatchSelectionKey(SelectionKey key) throws IOException {
if (key.isConnectable()) {
// socket connected
SocketChannel sc = (SocketChannel) key.channel();
// 判斷此通道上是否正在進行連接操作。
// 完成套接字通道的連接過程。
boolean f = sc.isConnectionPending();
if (f) {
boolean d = sc.finishConnect();
Log.e("aaaa", "=====finishConnect=====" + d);
if (d && connectedListener != null) {
connectedListener.onConnected();
}
} else {
Log.e("aaaa", "連接已斷開");
stop();
}
} else if (key.isReadable()) {
// msg received.
SocketChannel sc = (SocketChannel) key.channel();
int count = sc.read(temp);
if (count < 0) {//連接斷開
stop();
return;
}
// 切換buffer到讀狀態,內部指針歸位.
temp.flip();
String msg = Charset.forName("UTF-8").decode(temp).toString();
if (messageListener != null) {
messageListener.onReceivedMessage(msg);
}
// 清空buffer
temp.clear();
}
}
public void stop() throws IOException {
if (connectedListener != null) {
connectedListener.onDisconnected();
}
readBell.stop();
if (socketChannel != null)
socketChannel.close();
}
public interface OnConnectedListener {
void onConnected();
void onDisconnected();
}
/**
* 監聽客戶端發送來的消息
*
* @author zz
*/
public interface OnReceivedMessageListener {
/**
* 接收到消息
*
* @param msg 客戶端信息
*/
void onReceivedMessage(String msg);
}
}
第二步:創建SocketService.java類:
public class SocketService {private static ClientManager.OnConnectedListener connectedLis = new ClientManager.OnConnectedListener() {
@Override
public void onConnected() {
Log.e("aaaa", "-----Connected-----");
JSONObject jo = new JSONObject();
jo.put("act",1);
jo.put("data",App.getConfig());
ClientManager.getInstance().sendMessage(jo.toJSONString());
}
@Override
public void onDisconnected() {
Log.e("aaaa", "-----Disconnected-----");
}
};
private static ClientManager.OnReceivedMessageListener messageLis = new ClientManager.OnReceivedMessageListener() {
@Override
public void onReceivedMessage(String msg) {
Log.e("aaaa", "---msg----" + msg);
List<FrameInfo> infos = JSON.parseObject(msg, new TypeReference<List<FrameInfo>>() {
});
if (infos == null || infos.isEmpty())
return;
try {
ActiveAndroid.beginTransaction();
DBUtil.clearImageByType(1);
for (FrameInfo info : infos) {
info.setReserve(1);
info.save();
}
EventBus.getDefault().post(infos);
ActiveAndroid.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
ActiveAndroid.endTransaction();
}
}
};
public static void startService(String host, String port) {
ClientManager manager = ClientManager.getInstance();
manager.setOnConnectedListener(connectedLis);
manager.setOnReceivedMessageListener(messageLis);
manager.start(host, Integer.parseInt(port));
}
public static void stop() {
try {
ClientManager.getInstance().stop();
} catch (IOException e) {
e.printStackTrace();
}
}
}
第三步:在MainActivity.java類中調用開始方法
SocketService.startService("192.168.0.123","9090"); ?
轉載于:https://www.cnblogs.com/Sailsail/p/6612932.html
總結
以上是生活随笔為你收集整理的Socket实现java服务端与AndroidApp端数据交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Snipaste]系统截图工具
- 下一篇: DFiddler:A HTTP Pack