Socket编程总结—Android手机服务器与多个Android手机客户端之间的通信(非阻塞)
根据前两周写的关于Socket编程的网络通信的代码,现在对有关知识和注意事项进行总结如下:
1.首先说下Android NIO中有关Socket编程的类:
1)ServerSocketChannel类:服务器套接字通道相当于传统IO下的ServerSocket,通过ServerSocketChannel的socket()可以获得传统的ServerSocket,反过来使用ServerSocket的getChannel()可以获得ServerSocketChannel对象;实例化ServerSocketChannel可以直接通过ServerSocketChannel的静态方法open()就可以了。
2)SocketChannel类:套接字通道相当于传统IO下的Socket,通过SocketChannel的socket()可以获得传统的Socket,反过来使用Socket的getChannel()可以获得SocketChannel对象;
3)Selector选择器:在NIO中注册各种事件的方法主要使用Selector来实现的,我们可以使用Selector类的静态方法open()来实例化。
4)SelectionKey类:是个选择键,在NIO中选择器和选择键是很重要的,SelectionKey描述了NIO中比较重要的事件,如OP_ACCEPT、OP_READ、OP_WRITE。
2.然后说下非阻塞和阻塞模式的区别以及非阻塞模式的实现:
1)非阻塞:所谓非阻塞就是说,服务器监听客户端连接的时候,如果没有客户连接,程序还接续执行,不会停在这里等待客户连接;或者客户连接上了,下一步就是等待客户发数据,如果不发,程序不会停留在这里,而是继续执行。反过来停留在这里,不继续执行就是阻塞。
2)非阻塞模式的实现:对于客户端来说,得到SocketChannel对象后,通过调用方法configureBlocking(false)来设置这个Socket为非阻塞状态。然后在配合Selector和SelectionKey的使用来与服务器进行交互。代码如下:
SocketChannel socket = new SocketChannel(ip,port);
socket.configureBlocking(false);
mSelector = Selector.open();
socket.register(mSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
while (true) {
mSelector.select(0);
Set<SelectionKey> readKeys = mSelector.selectedKeys();
Iterator<SelectionKey> iterator = readKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isReadable()) {.....
} else if (key.isWritable()) {.....
}
}
}
3. 消息处理机制—Message Handler Looper
Message消息 Handler处理发送和接收消息 Looper管理消息,就是一个手柄
在什么情况下使用消息呢?比如一个子线程,在执行过程中要更改主线程UI的一个控件值,这个时候就需要发送一个消息给主线程,而使用消息处理机制也可以不干扰主线程执行其他操作,在主线程中只要Handler感应到有信息过来它会自己接收,然后处理。代码如下:
在主线程:声明一个Handler
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
在子线程:
public void sendMessage(String message, int what) {
Message msg = mHandler.obtainMessage(what, 1, 1, message);
mHandler.sendMessage(msg);
}
注意子线程中的Handler必须是主线程声明的Handler,这样子线程发送的消息才能被主线程Handler认识接收。
4.遇到的问题
1)线程问题:Socket编程中,实现服务器与多个客户端的通信要尽量用多线程机制来实现,当服务器监听到一个客户端的连接就开辟一个线程专门负责与客户端的通信,如果客户端因为某个原因断开与服务器的连接就要及时关闭线程;当然如果是服务器断开了,那么就要关闭所有与客户通信的线程。Android开发中,要注意一点,比较耗时的操作最好开辟一个线程单独执行,不然主线程因为执行这个耗时的操作而耽误执行其他操作,这样导致程序效率很差。
2)网络问题:Android开发中,往往遇到服务器与客户端正在通信时候突然网络断了,这个时候就要关闭socket,但是在关闭socket的时候,双方要知道网络断了才能关闭,如果是人为关闭socket,另一方肯定能检测到,但是是网络突然断开,就不能检测到了,解决这样的方法就是,双方连接上后,每隔一段时间发一个保护数据包,这个数据包双方只管发送,接收不进行处理,如果在一段时间内,一方既没有发送正常的数据包也没有发送保护数据包,那就关闭socket,这样就解决了网络断开的问题导致一方没有及时关闭socket的问题。
3)socket关闭问题:在进行socket编程中,遇到异常或者其他需要断开连接的情况时,socket要及时关闭,而在关闭socket之前,要保证线程关闭;举个列子说下,客户端人为断开与服务器的连接,此时服务器就会检测到与这个客户的通道已经关闭而出现异常,此时服务器就要关闭线程和socket。
还有一个特别重要的问题,在Android开发中,如果服务器与客户端通信的时候,如果没有定义一个协议,只是简单的发送一个字符串,那么如果某一方发送一个空值,这个时候另一方就会默认的认为你没有发送数据。解决这个问题的办法就是,要么定义一个规范的协议发送数据,也就是每发送一个数据都有一个头,要么定义一个专门的数据包(如byte类型的 1 )代表一个空值。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
获取手机IP地址
第一种:
public int getIpAddress() {
WifiManager wifiManager = (WifiManager) this.context
.getSystemService(Context.WIFI_SERVICE);
// 判断wifi是否开启
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return ipAddress;
}
private String intToIp(int i) {
return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF)
+ "." + (i >> 24 & 0xFF);
}
第二种:
public String getInetIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> ipAddr = intf.getInetAddresses(); ipAddr
.hasMoreElements();) {
InetAddress inetAddress = ipAddr.nextElement();
return inetAddress.getHostAddress();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
转载于:https://www.cnblogs.com/crearo-ssy/archive/2012/08/16/2640612.html
Socket编程总结—Android手机服务器与多个Android手机客户端之间的通信(非阻塞)相关推荐
- 手机服务器艰辛之路(一)~手机服务器环境部署
手机服务器艰辛之路(一)~手机服务器环境部署 前言 随着博主使用服务器的依赖性越来越高,之前一直是99元白嫖阿里云服务器,但是每年都会遇到相同的一个问题"是否还需要续费?". 答案 ...
- 服务器端和客户端互发消息,Socket编程实现简单的服务器与客户端互发消息
socket编程的大致步骤如下: 1.创建服务器端SocketServer,并定义SocketServer的监听端口; 2.ServerSocket调用accept( )方法,是指处于阻塞: 3.创建 ...
- android 对讲机 服务器,对讲机功能与Android 4.0系统_手机_手机Android频道-中关村在线...
对讲功能与Android 4.0系统 Runbo X5三防手机此次采用了比较主流的Android 4.0系统,但是系统基本为原生,并没有太多的定制:不过就像是军车的设计从来都是以性能而不是以车内的豪华 ...
- 怎么修复手机服务器,新手机怎么恢复旧手机上的所有数据?
将旧手机中所有数据迁移至新手机,大体上分为两种类型.一类是同品牌不同型号之间的数据迁移,一类是不同品牌不同机型之间的数据迁移.如果是第一种情况较为简便,利用手机厂商提供的软件服务器即可实现,第二种情况 ...
- 手机服务器密码在什么位置,手机远程云服务器登录密码是什么
手机远程云服务器登录密码是什么 内容精选 换一换 只有运行中的云服务器云主机才允许用户登录.Windows操作系统用户名"Administrator".首次登录云耀云服务器,请先通 ...
- 手机服务器缓存在什么位置,手机服务器缓存设置方法
手机服务器缓存设置方法 内容精选 换一换 登录Windows操作系统的裸金属服务器时,需使用密码方式登录.因此,用户需先根据创建裸金属服务器时使用的密钥文件,获取该裸金属服务器初始安装时系统生成的管理 ...
- 如何知道自己手机服务器在哪个文件夹,手机设置服务器在哪个文件夹下
手机设置服务器在哪个文件夹下 内容精选 换一换 Cloud-Init工具安装完成后,请参考本节操作配置Cloud-Init工具.已安装Cloud-Init工具.已为云服务器绑定弹性公网IP.已登录云服 ...
- 云手机虚拟手机服务器在哪里,云端虚拟手机服务器
云端虚拟手机服务器 内容精选 换一换 本文介绍了主机迁移服务SMS各特性版本的功能发布和对应的文档动态,新特性将在各个区域(Region)陆续发布,欢迎体验. 迁移前,您需要设置目的端服务器.该目的端 ...
- C++socket编程(三):3.6 服务端recv客户端发送的数据
服务端中获取客户端发送过来的数据一定是关闭套接字之前进行,close之后就收不到数据了. 一般读取数据一般用read,windows上一般用recv(本质上也是read),但是为了跨平台,所以一般用r ...
最新文章
- 攻破JAVA NIO技术壁垒
- 互信息的数学解释以及matlab编程
- sonar findbugs plugin源码研究
- java 域_java四大域总结
- Java实现MD5加密解密类
- ios原生条形码扫描 效率低下原因
- python基础教程python详细教程
- org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException
- 深度学习模型压缩与优化加速
- 数学三次危机(三)“希帕索斯悖论”或“毕达哥拉斯悖论”
- 【央联众商】进行家庭投资理财选择的必要性
- confirm-order提交订单
- 体脂秤方案——体脂秤的原理是什么?
- 第一步:搭建项目基本框架
- 组词组合 php,PHP实现的简单组词算法示例讲解
- 解决maven打包时手动添加的依赖jar包打不进去的情况
- acwing280.陪审团 01背包
- Linux文件目录操作命令-mkdir命令
- Linux的Vim文本编辑器
- 2022-2028年全球与中国运动钓鱼用具行业市场需求预测分析