,,Android完整Socket解决方案

,,Android完整Socket解决方案

本文主要介绍Android完整的Socket解决方案,并通过代码给大家一个实例分析。有兴趣的可以借鉴一下。

整体步骤流程

先说整体步骤:

发送UDP广播,众所周知,UDP广播的特点是整个网段内的所有设备都可以接收到这个消息。

接收方接收UDP广播,并将其ip地址和双方同意的端口号回复给UDP发送方。

当发送方获得对方的ip地址和端口号后,就可以发起TCP请求,建立TCP连接。

保持TCP心跳。如果发现对方不在了,超时后重复步骤1重新建立联系。

整体步骤和上面说的一样,下面是代码扩展:

搭建 UDP 模块

公共UDPSocket(上下文context) {

this.mContext=context

int cpuNumbers=runtime . get runtime()。available processors();

//根据CPU数量初始化线程池

mThreadPool=executors . newfixedthreadpool(cpuNumbers * Config。POOL _ SIZE);

//记录对象的创建时间

lastreeceivetime=system . current time millis();

messageReceiveList=new ArrayList();

Log.d(标签,'创建UDP对象');

//create user();

}

首先做一些初始化,准备线程池,记录对象的初始时间等等。

public void startUDPSocket() {

如果(客户端!=null)返回;

尝试{

//指示此套接字在设置的端口上侦听数据。

CLIENT=new datagram socket(CLIENT _ PORT);

client . setreuseaddress(true);

if (receivePacket==null) {

//创建接受数据的数据包

receive packet=new datagram packet(receive byte,BUFFER _ LENGTH);

}

startSocketThread();

} catch (SocketException e) {

e . printstacktrace();

}

}

然后创建一个真正的UDP套接字DatagramSocket。注意,这里传递的端口号CLIENT_PORT意味着这个DatagramSocket在这个端口号上接收消息。

/**

*打开线程发送数据。

*/

私有void startSocketThread() {

clientThread=新线程(new Runnable() {

@覆盖

公共无效运行(){

receive message();

}

});

isThreadRunning=true

client thread . start();

Log.d(标签,'打开UDP数据接收线程');

startheartbeatimer();

}

我们都知道Socket处理数据的发送和接收,发送和接收都是阻塞的,所以要放在一个子线程里。这里打开一个线程处理接收到的UDP消息(关于UDP模块的上一篇文章已经详细描述了,这里就不详细展开了)

/**

*处理收到的消息。

*/

私有void receiveMessage() {

while (isThreadRunning) {

尝试{

如果(客户端!=null) {

client.receive(接收数据包);

}

lastreeceivetime=system . current time millis();

Log.d(标签,'接收数据包成功.');

} catch (IOException e) {

Log.e(TAG,' UDP数据包接收失败!停止线程’);

stopUDPSocket();

e . printstacktrace();

返回;

}

if(receive packet==null | | receive packet . getlength()==0){

Log.e(标签,'无法接收UDP数据或者接收到的UDP数据为空');

继续;

}

String strReceive=new String(receive packet . get data()、receivePacket.getOffset()、receive packet . getlength());

Log.d(TAG,str receive ' from ' receive packet . get address()。getHostAddress()':' receive packet . get port());

//解析收到的json信息

notifyMessageReceive(strReceive);

//每次收到UDP数据后重置长度。否则,下一个接收的分组可能被截断。

if(接收数据包!=null) {

receive packet . setlength(BUFFER _ LENGTH);

}

}

}

UDP数据在子线程中接收,notifyMessageReceive方法通过接口通知消息。

/**

*发送到心跳包

*

* @param消息

*/

公共void sendMessage(最终字符串消息){

mThreadPool.execute(新的Runnable() {

@覆盖

公共无效运行(){

尝试{

BROADCAST _ IP=wifi util . getbroadcastaddress();

Log.d(标签,' BROADCAST _ IP:' BROADCAST _ IP ');

inet地址targetAddress=inet地址。按名称获取(BROADCAST _ IP);

数据报数据包=新的数据报数据包(消息。getbytes()、message.length()、targetAddress、CLIENT _ PORT);

客户端发送(数据包);

//数据发送事件

Log.d(标签,'数据发送成功');

} catch (UnknownHostException e) {

e。printstacktrace();

} catch (IOException e) {

e。printstacktrace();

}

}

});

}

接着开始心跳计时器开启一个心跳线程,每间隔五秒,就去广播一个用户数据报协议(用户数据报协议)消息。注意这里getBroadcastAddress是获取的网段ip,发送这个用户数据报协议(用户数据报协议)消息的时候,整个网段的所有设备都可以接收到。

到此为止,我们发送端的用户数据报协议(用户数据报协议)算是搭建完成了。

搭建 TCP 模块

接下来传输控制协议(传输控制协议)模块该出场了,UDP发送心跳广播的目的就是找到对应设备的互联网协议(互联网协议的缩写)地址和约定好的端口,所以在用户数据报协议(用户数据报协议)数据的接收方法里:

/**

* 处理用户数据报协议收到的消息

*

* @param消息

*/

私有void handleUdpMessage(字符串消息){

尝试{

JSON对象JSON对象=新JSON对象(消息);

字符串IP=JSON对象。optstring(配置.TCP _ IP);

字符串port=JSON对象。optstring(配置.TCP _ PORT);

如果(!TextUtils.isEmpty(ip)!TextUtils.isEmpty(port)) {

startTcpConnection(ip,port);

}

} catch (JSONException e) {

e。printstacktrace();

}

}

这个方法的目的就是取到对方UDPServer端,发给我的用户数据报协议(用户数据报协议)消息,将它的互联网协议(互联网协议的缩写)地址告诉了我,以及我们提前约定好的端口号。

怎么获得一个设备的互联网协议(互联网协议的缩写)呢?

公共字符串getLocalIPAddress() {

wifi信息wifi信息=mwifimanager。获取连接信息();

返回intto IP(wifi信息。getip地址());

}

私有静态字符串intToIp(int i) {

return (i0xFF)' . '((i 8)0xFF)' . '((i 16)0xFF)' . '

((I 24)0x ff);

}

现在拿到了对方的ip,以及约定好的端口号,终于可以开启一个传输控制协议(传输控制协议)客户端了。

私有布尔startTcpConnection(最终字符串ip,最终(同Internationalorganizations)国际组织端口){

尝试{

if (mSocket==null) {

mSocket=新套接字(ip,端口);

m插座。setkeepalive(true);

msocket。setcpnodelay(true);

msocket。setreuseaddress(true);

}

InputStream是=m套接字。getinputstream();

br=新缓冲读取器(新InputStreamReader(is));

输出流OS=m套接字。获取输出流();

pw=new PrintWriter(新缓冲写入器(新输出streamwriter(OS)),true);

Log.d(标记,' tcp创建成功.');

返回真实的

} catch(异常e) {

e。printstacktrace();

}

返回错误的

}

当传输控制协议(传输控制协议)客户端成功建立的时候,我们就可以通过传输控制协议(Transmission Control Protocol)套接字来发送和接收消息了。

细节处理

接下来就是一些细节处理了,比如我们的用户数据报协议(用户数据报协议)心跳,当传输控制协议(传输控制协议)建立成功之时,我们要停止用户数据报协议(用户数据报协议)的心跳:

if (startTcpConnection(ip,Integer.valueOf(port))) {//尝试建立传输控制协议(传输控制协议)连接

if (mListener!=null) {

m听众。成功时();

}

startReceiveTcpThread();

startheartbeatimer();

}否则{

if (mListener!=null) {

m听众。在失败(配置错误代码。创建_ TCP _错误);

}

}

//TCP已经成功建立连接,停止用户数据报协议(用户数据报协议)的心跳包。

public void stopfheartbeatimer(){

如果(定时器!=null) {

计时器。exit();

计时器=空

}

}

对传输控制协议(传输控制协议)连接进行心跳保护:

/**

* 启动心跳

*/

private void startHeartbeatTimer(){

if (timer==null) {

timer=新心跳计时器();

}

timer.setOnScheduleListener(新心跳计时器OnScheduleListener() {

@覆盖

公共计划无效(){

Log.d(标签,'计时器按计划运行.');

持续时间长=系统。当前时间毫秒()-上次接收时间;

Log.d(标签,' duration:' duration ');

如果(持续时间超时){//若超过十五秒都没收到我的心跳包,则认为对方不在线。

Log.d(标记,' tcp ping超时,对方已经下线');

stopTcpConnection();

if (mListener!=null) {

m听众。在失败(配置错误代码。PING _ TCP _超时);

}

} else If(duration heart beat _ message _ duration){//如果他超过两秒没有收到我的心跳包,再发一个。

JSON object JSON object=new JSON object();

尝试{

jsonObject.put(Config。消息,配置。平);

} catch (JSONException e) {

e . printstacktrace();

}

sendTcpMessage(JSON object . tostring());

}

}

});

timer.startTimer(0,1000 * 2);

}

首先,每隔两秒钟,我会给对方发一个ping包,看看对方是否在。如果超过15秒还没人接,说明对方断线了,关闭我的TCP端。输入onFailed方法。

@覆盖

公共void on失败(int错误代码){//TCP异常处理

开关(错误代码){

案例配置。错误代码。CREATE_TCP_ERROR:

打破;

案例配置。错误代码。PING_TCP_TIMEOUT:

UDP socket . startheartbeattimer();

tcpSocket=null

打破;

}

}

当TCP连接超时时,我将重新启动UDP广播心跳,并寻找等待连接的设备。进入下一步循环。

对于数据传输的格式等细节,这是和业务有关的。你自己决定吧。

你也可以根据你的业务模式开启不同的线程通道,无论是CPU密集型还是IO密集型。这就涉及到螺纹的知识了。

源代码共享:https://github.com/itsMelo/AndroidSocket

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • windowsandroid手机版下载,windowsandroid安装apk
  • windowsandroid手机版下载,windowsandroid安装apk,WindowsAndroid 安装教程详解
  • android调用webview方法,androidwebview是什么,Android 中 WebView 的基本用法详解
  • android传感器高级编程,Android传感器,Android编程之光线传感器用法详解
  • android.app.Dialog,android自定义dialog对话框,Android开发笔记之-Dialog的使用详解
  • android 图片视频轮播框架,androidlayout轮播图,Android实现炫酷轮播图效果
  • android里的viewpager,安卓自定义view流程,Android自定义引导玩转ViewPager的方法详解
  • android里的viewpager,android viewpager详解
  • android里的viewpager,android viewpager详解,Android自定义超级炫酷的ViewPage指示器
  • android调用webview方法,androidwebview是什么
  • android设置控件宽度,android获取屏幕宽度和高度
  • android设置控件宽度,android获取屏幕宽度和高度,Android中获取控件宽高的4种方法集合
  • android蓝牙开发的基本流程,安卓蓝牙app开发教程
  • android蓝牙开发的基本流程,安卓蓝牙app开发教程,android蓝牙简单开发示例教程
  • android菜单栏,android菜单控件
  • 留言与评论(共有 条评论)
       
    验证码: