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)的更多相关文章

  1. unity3d,java,c#,python,rospy的socket通信测试

    1.C#在与其他人通信时,最好不要用tcpclient来承接其他语言,会收不到用户名,最好都用socket. 2.unity3d在与java通信时,对方返回我unity3d发的数据流会打印收到一个类, ...

  2. Android和C#实时视频传输Demo

    说起去年的Demo.以今天的免费整齐优势. 原理很easy,虽然没有写android申请书.但,好了~ 高级语言是相通的.傲慢约.就这么简单研究了一下api后,找到相机对象有一个预览回调方法. 意识到 ...

  3. 热情组——项目冲刺 Day5

    项目相关 作业相关 具体描述 班级 班级链接 作业要求 链接地址 团队名称 热情组 作业目标 实现软件制作,以及在福大的传播 Github链接 链接地址 SCRUM部分: 成员昵称 昨日目标 开始时间 ...

  4. 安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制

    安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制 socket 连接采用流的方式进行发送接收数据,采用thread线程的方式. 什么是线程?  详细代码介 ...

  5. 安卓socket聊天

    安卓基于Socket通信(服务器配合) 1.话不多说进入正题,先创建服务端,在Android Studio中创建Java代码,如下图所示: 选择Java Library 需要改名字的自己随意 2.创建 ...

  6. Web实时通信之Socket.IO

    前面两篇文章使用了Ajax long polling和WebSocket两种常用的Web实时通信方式构建了简单的聊天程序. 但是,由于浏览器的兼容问题,不是所有的环境都可以使用WebSocket这种比 ...

  7. 用Socket开发的一枚小型实时通信App

    Socket 英文原意是插座. 在网络世界里, 当一台主机温柔而体贴的同时提供多个服务时, 每个服务被绑定在一个端口上, 而每个端口就好像一个小插座. 用户们连接对应的插座去获取相应的服务. 在Nod ...

  8. 安卓Socket开发注意事项

    如果要在安卓app里用到Socket通信,要满足: 1.在写代码的activity里import进Socket相关的包,这个很easy,如果你不知道要import什么包,也可以先不指定,可       ...

  9. 安卓使用Socket发送中文,C语言服务端接收乱码问题解决方式

    今天用安卓通过Socket发送数据到电脑上使用C语言写的服务端,发送英文没有问题,可当把数据改变成中文时,服务端接收到的数据确是乱码. 突然想到.VS的预处理使用的是ANSI编码.而安卓网络数据都是U ...

随机推荐

  1. 旅游类的APP原型模板分享——Priceline

    Priceline是一款旅游服务的APP应用.功能有查找预订酒店.车票.机票等服务. 本原型由国产Mockplus(原型工具)和iDoc(智能标注,一键切图工具)提供. 先简单看看动图: 点击这里,可 ...

  2. 一次HTTP请求响应涉及了哪些?

    HTTP请求和响应步骤 TCP/IP协议 TCP三次握手 HTTP协议 HTTP请求报文 HTTP响应报文 TCP四次挥手 HTTP请求和响应步骤 以上完整表示了HTTP请求和响应的7个步骤,下面从T ...

  3. hibernate中怎样配置两个联合属性为唯一约束(非联合主键)

    Annotation中配置: @Table元素包括了一个schema和一个catalog属性,如果需要可以指定相应的值. 结合使用@UniqueConstraint注解可以定义表的唯一约束(uniqu ...

  4. k8s 安装步骤

    1 安装Docker 1.1 增加中国区镜像 https://registry.docker-cn.com 2 下载安装k8s的镜像的脚本 https://github.com/AliyunConta ...

  5. MongoDB + Express 环境搭建记

    最近项目需要使用 MongoDB,所以不得不搭建 MongoDB 环境,此文记录搭建过程及使用过程中需要了解的问题. Linux + Windows 混合搭建调试 MongoDB 记录 版本介绍 : ...

  6. 在不安装sqlite3的时候使用sqlite3数据库以及问题/usr/bin/ld: skipping incompatible.....的解决

    在没有安装sqlite3的linux机器上,怎么在不安装的情况下使用sqlite3的数据库呢: 其中只需要2个文件即可: 数据库的动态库libsqlite3.so,sqlite3.h. 另外,一些系统 ...

  7. javascript_01

  8. 记一次需要用到复杂的groupingBy的需求

    一:先定义结构 public class Foo { private Integer id; private String name; private BigDecimal amount; publi ...

  9. 如何往有自增标识字段的表插入数据时,同时给自增标识字段插入值呢,在Inset Into语句前后加上SQL语句:SET IDENTITY_INSERT TableName ON和SET IDENTITY_INSERT TableName OFF

    当要往有设置自增标识字段的表插入数据,并希望同时设置好自增字段的值时,可以在insert into 的SQL语句前后分别加上一句sql语句,SET IDENTITY_INSERT TableName  ...

  10. 排序算法 (sorting algorithm)之 冒泡排序(bubble sort)

    http://www.algolist.net/Algorithms/ https://docs.oracle.com/javase/tutorial/collections/algorithms/ ...