安卓之必须了解的实时通信(Socket)
Socket:
有服务器和客户端之分,其是对TCP/IP的封装,使用IP地址加端口,确定一个唯一的点。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。值得注意的是用户使用的端口最好大于1024,因为小于1024的大部分端口都是被系统占用的。此章将实现安卓socket客户端编程。
安卓的线程基本机制
一个程序就是一个进程,一个进程里可以有多个线程,每个进程必须有一个主线程。对应安卓一个应用程序就是一个进程,其主线程就是平常所说的安卓主UI线程。安卓实现多线程编程,其有一个重要的原则就是更新UI必须在主线程,但耗时操作必须在子线程中,如果耗时操作在主线程编写(如网络访问)当阻塞时间达到一定时,应用就会强制退出,那网络访问就面临着一个不可避免的问题:子线程更新UI操作如何实现。
Handler
Handler主要用于异步消息的处理: 有点类似辅助类,封装了消息投递、消息处理等接口。当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。
Message
Handler接收与处理的消息对象,其中消息类型有
public int arg1和public int arg2:存放简单的整数类型消息
public Object obj:发送给接收器的任意对象,不管是整数,字符串,某个类对象均可
public int what:用户自定义的消息代码,这样接受者可以了解这个消息的信息,每个handler各自包含自己的消息代码,所以不用担心自定义的消息跟其他handlers有冲突。
安卓端实现效果
在同一网络下的一个设备开启一个端口的监听,做为socket服务器,并获取到服务器设备的IP地址和端口号,将其格式化为 “IP:端口” 进行输入,如 “193.169.44.198:8081” ,点击连接即可。安卓作为socket客户端与服务器交互数据。
编程实现
获取网络访问权限:
实现socket编程,必须开启网络访问权限
<uses-permission android:name="android.permission.INTERNET" />
编写Handler消息处理类:
handler消息处理类是MainActivity类的内部类,当消息队列不为空时将自动进入,获取到消息值并分析其中内容
private Handler mainhandler=new Handler(){
@Override
public void handleMessage(Message msg) {
//获取到命令,进行命令分支
int handi=msg.arg1;
switch (handi){
case 0:
String ormsg=(String)msg.obj;
disSocket();//断开网络
Toast.makeText(MainActivity.this,"发生错误=>:"+ormsg,Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show();
break;
case 2:
//收到数据
String str1=(String)msg.obj;
main_rx.setText(str1);
break;
default:break;
}
}
};
连接按钮监听:
当连接按钮按下时,将会立即获取输入框的内容并进行字符串分隔,得到IP地址和端口号,开启线程进行网络连接
//连接按钮监听
main_conn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String strip=main_ip.getText().toString().trim();
if(strip.indexOf(":")>=0){ //开始启动连接线程
new Socket_thread(strip).start(); } }
});
发送数据按钮监听:
当发送数据按钮按下时,将会立即获取到发送输入框的内容,分别可以调用字符串发送函数和十六进制发送函数进行数据发送
//发送按钮监听
main_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//得到输入框内容
final String senddata=main_tx.getText().toString().trim(); if(!senddata.equals("")){
//发送因为使用的是线程,所以先后顺序不一定
//发送字符串数据
sendStrSocket(senddata);
//发送十六进制数据
sendByteSocket(new byte[]{0x01,0x02,0x03}); }else Toast.makeText(MainActivity.this,"输入不可为空",Toast.LENGTH_SHORT).show();
}
});
开始网络连接线程:
该类为MainActivity类的内部类,实现线程连接socket服务器,并获取输入输出流,并开启接收线程
class Socket_thread extends Thread
{
private String IP="";//ip地址
private int PORT=0;//端口号
public Socket_thread(String strip){
//构造方法需要传递服务器的IP地址和端口号
//如: 192.168.43.222:8099
//进行字符串分隔,得到服务器IP地址和端口号
String[] stripx= strip.split(":");
this.IP=stripx[0];
this.PORT=Integer.parseInt(stripx[1]);
}
@Override
public void run() {
try { disSocket();//断开上次连接
if(sock !=null){
outx.close();
inx.close();
sock.close();//关闭
sock=null;
}
//开始连接服务器,此处会一直处于阻塞,直到连接成功
sock=new Socket(this.IP,this.PORT); //阻塞停止,表示连接成功,发送连接成功消息
Message message=new Message();
message.arg1=1;
mainhandler.sendMessage(message); }catch (Exception e) {
Message message=new Message();
message.arg1=0;
message.obj="连接服务器时异常";
mainhandler.sendMessage(message); System.out.println("建立失败////////////////////////////////////////////");
e.printStackTrace();
return;
}
try {
//获取到输入输出流
outx=sock.getOutputStream();
inx=sock.getInputStream();
} catch (Exception e) {
//发送连接失败异常
Message message=new Message();
message.arg1=0;
message.obj="获取输入输出流异常";
mainhandler.sendMessage(message); System.out.println("流获取失败////////////////////////////////////////////");
e.printStackTrace();
return;
} // new Outx().start();
new Inx().start();
}
}
关闭socket函数:
关闭socket之前将先关闭输入输出流,这样才能更加安全的关闭socket
private void disSocket(){
//如果不为空,则断开socket
if(sock !=null){
try {
outx.close();
inx.close();
sock.close();//关闭
sock = null;
}catch (Exception e){
//发送连接失败异常
Message message=new Message();
message.arg1=0;
message.obj="断开连接时发生错误";
mainhandler.sendMessage(message); }
} }
数据接收线程实现:
接收线程将实现数据的接收,并把接收到的数据通过消息发送给处理类,特别注意的是 inx.read(bu) 返回如果是 -1 则表示服务器断开了连接或者其它非主动调用关闭socket方法断开造成的错误
//循环接收数据
class Inx extends Thread{
@Override
public void run() {
while(true){ byte[] bu=new byte[1024];
try {
//得到-1表示服务器断开
int conut=inx.read(bu);//设备重启,异常 将会一直停留在这
if(conut==-1){
//发送连接失败异常
Message message=new Message();
message.arg1=0;
message.obj="服务器断开";
mainhandler.sendMessage(message);
disSocket();//断开连接
System.out.println("**********服务器异常*********:"+conut);
return;
} //必须去掉前后空字符,不然有这个会有1024个字符每次
strread=new String(bu,"GBK").trim();
//发送出收到的数据
Message message=new Message();
message.arg1=2;
message.obj=strread;
mainhandler.sendMessage(message); } catch (IOException e) {
System.out.println(e); }
} }}
发送字符串函数:
网络编程的最终发送的内容是字节,所以发送字符串需要通过getBytes进行编码
//发送字符串
private void sendStrSocket(final String senddata){
new Thread(new Runnable() {
@Override
public void run() {
try {
//可以经过编码发送字符串
outx.write(senddata.getBytes("gbk"));//"utf-8" } catch (Exception e) {
//发送连接失败异常
Message message=new Message();
message.arg1=0;
message.obj="数据发送异常";
mainhandler.sendMessage(message);
}
}
}).start();
}
发送十六进制函数:
通过字节数组,可以实现多个十六进制数据的发送
//发送十六进制
private void sendByteSocket(final byte[] senddata){
new Thread(new Runnable() {
@Override
public void run() {
try {
//发送十六进制
outx.write(senddata); } catch (Exception e) {
//发送连接失败异常
Message message=new Message();
message.arg1=0;
message.obj="数据发送异常";
mainhandler.sendMessage(message);
}
}
}).start();
}
参考:
https://blog.csdn.net/rabbit_in_android/article/details/50585156
https://www.imooc.com/article/25134?block_id=tuijian_wz
安卓之必须了解的实时通信(Socket)的更多相关文章
- unity3d,java,c#,python,rospy的socket通信测试
1.C#在与其他人通信时,最好不要用tcpclient来承接其他语言,会收不到用户名,最好都用socket. 2.unity3d在与java通信时,对方返回我unity3d发的数据流会打印收到一个类, ...
- Android和C#实时视频传输Demo
说起去年的Demo.以今天的免费整齐优势. 原理很easy,虽然没有写android申请书.但,好了~ 高级语言是相通的.傲慢约.就这么简单研究了一下api后,找到相机对象有一个预览回调方法. 意识到 ...
- 热情组——项目冲刺 Day5
项目相关 作业相关 具体描述 班级 班级链接 作业要求 链接地址 团队名称 热情组 作业目标 实现软件制作,以及在福大的传播 Github链接 链接地址 SCRUM部分: 成员昵称 昨日目标 开始时间 ...
- 安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制
安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制 socket 连接采用流的方式进行发送接收数据,采用thread线程的方式. 什么是线程? 详细代码介 ...
- 安卓socket聊天
安卓基于Socket通信(服务器配合) 1.话不多说进入正题,先创建服务端,在Android Studio中创建Java代码,如下图所示: 选择Java Library 需要改名字的自己随意 2.创建 ...
- Web实时通信之Socket.IO
前面两篇文章使用了Ajax long polling和WebSocket两种常用的Web实时通信方式构建了简单的聊天程序. 但是,由于浏览器的兼容问题,不是所有的环境都可以使用WebSocket这种比 ...
- 用Socket开发的一枚小型实时通信App
Socket 英文原意是插座. 在网络世界里, 当一台主机温柔而体贴的同时提供多个服务时, 每个服务被绑定在一个端口上, 而每个端口就好像一个小插座. 用户们连接对应的插座去获取相应的服务. 在Nod ...
- 安卓Socket开发注意事项
如果要在安卓app里用到Socket通信,要满足: 1.在写代码的activity里import进Socket相关的包,这个很easy,如果你不知道要import什么包,也可以先不指定,可 ...
- 安卓使用Socket发送中文,C语言服务端接收乱码问题解决方式
今天用安卓通过Socket发送数据到电脑上使用C语言写的服务端,发送英文没有问题,可当把数据改变成中文时,服务端接收到的数据确是乱码. 突然想到.VS的预处理使用的是ANSI编码.而安卓网络数据都是U ...
随机推荐
- NOIP2018游记(划掉) 滚粗记
Day0 早上摸鱼~, 打几个板子就颓废 中午出发, 在火车上颓元气+睡觉. 到了宾馆发现yhx已经帮我们拿了袋子和狗牌,于是上楼欢乐地搓起了六家统, 一直搓到10点钟才回自己房间. 有六家统就有快乐 ...
- Python用HTMLTestRunner生成html测试报告
小编的主机:mac 一.引入HTMLTestRunner包 1.下载HTMLTestRunner.py,已上传到网盘,点击下载 2.将HTMLTestRunner.py复制到python安装目录的Li ...
- 深入理解JVM(七)JVM类加载机制
7.1JVM类加载机制 虚拟机把数据从Class文件加载到内存,并且校验.转换解析和初始化最终形成可以被虚拟机使用的Java类型,这就是虚拟机的类加载机制. 7.2类加载的时机 1.类加载的步骤开始的 ...
- IEC2017级_1-2班2次博客作业成绩说明
一.博客作业内容 2018上IEC计算机高级语言(C)作业 第2次作业 二.评分规则说明 1.程序调试题,要描述出调试所遇到问题及修改内容,并表述清楚程序功能.流程图不规范的会减1-2分: 2.知识点 ...
- PYTHON基础入门(内置函数、推导式)学习
**内建函数**1.通过使用dir()函数可以列出所具备的方法 例:num = 10 dir(num) 例:myList = [1,2,3,4,5,6] dir(num)2.通过使用help()函数可 ...
- PID25 / 合并果子 ☆
这里用到了STL里面的priority_queue,我也不是很精通基本上属于现学现卖阶段,http://www.cnblogs.com/flyoung2008/articles/2136485.htm ...
- AspNetCore中的IdentityServer4客户端认证模式实现
1 AuthorizationServer using IdentityServer4; using IdentityServer4.Models; public class Startup { pu ...
- HTTPie命令介绍
HTTPie 是一个 HTTP 的命令行客户端.其目标是让 CLI 和 web 服务之间的交互尽可能的人性化.HTTPie 可用于与 HTTP 服务器做测试.调试和常规交互. 1 定制 HTTP 方法 ...
- web安全系列3:http拦截
这是web安全系列第三篇,我们讲讲HTTP请求的拦截.关于http的内容请翻看我的上一篇文章. 首先,我们开始需要一个安装好的java环境,64位的.请自行安装和配置环境变量,如果遇到问题可以留言评论 ...
- 将n个东西分成n1,n2,n3,n4,....nr 共 r组分给r个人有多少种分法。
(n!/(n1! *n2! *n3!..nr!) ) * r!/( 同数量组A的数量! 同数量组B的数量!....) 比方20个东西分成2,2,,2,2 3,3,3,3 8组分给8个人有多少种 ...