技术标签: 通讯 网络 服务器 socket Android实战开发 Android
欢迎转载,转载请注明出处:http://blog.csdn.net/dmk877/article/details/51685656
Hello,大家好,今天又来写博客了,项目终于搞完了最近又有时间写写博客了。在上上篇博客中我们学习了Android中网络通讯,并用Socket实现了Android客户端与服务器的通讯,那么这一篇将进一步来完善这一功能,就是要实现两个android手机端的通讯。
如有谬误,欢迎批评指正,如有疑问欢迎留言
通过本篇博客你将学到以下知识点
①Socket的用法
②如何实现两个手机的端的通讯
③JAVA中的流的小知识
在开始之前我们先来分析以下如何实现这个通讯,首先来考虑这么几个问题
①这种实时的通讯应采取哪种通讯方式
②怎么保证是消息能到达我们想发送的那一方,也就是说A想与B交流怎么保证B收到的消息是A发过来的
③怎么保证消息的实时性,也就是说A发一条消息B能实时收到。
要想回答这三个问题其实不难,读过Android开发之网络通讯详解这篇博客的童鞋应该知道,这种及时性比较高的通讯一般采用Socket这种通讯方式,而对于第二个问题如果想让消息到达我们的指定方,针对A和B需要有一个唯一的标识,这个标识我们可以自己定义,在本文中采用的策略是为A和B定义一个ID来唯一的确定它,在A用户发送消息的时候只要指定它想把消息发送到的那个用户的ID就能保证B收到的消息是A发过来的。保证消息的实时性也就是通过使用Socket来解决的。
通讯的过程图解
从上图我们可以清楚的看到整个过程服务器充当的是一个中转的作用,clientSocket1首先会将消息封装成json发送给服务器,服务器解析后再封装将消息发送给clientSocket2。
客户端的运行效果图(注意:下面是一整张图,是一张图片):
上述运行效果就实现了两个Android机的相互通讯。两个客户端分配的id分别为0和1。在发送消息时需要指定消息的到达方。
3.1 客户端发送消息实现步骤
第一步需要做的当然就是连接到服务器,连接服务器的方法为
clientSocket=new Socket(ip,port);
即设置服务器的ip和端口号,建立连接之后通过while(true)就可以不断的监听服务器是否发送过来消息了。
第二步就是要输入你要发送的好友的id号,这样就能保证你发送的消息能按照你的预期到达接收方。
第三步就是发送消息了在发送消息的时候需要注意,我们是把消息封装成json发过去的,这个json中包含哪些信息呢?有三种信息①消息发送方id②消息的内容③消息到达方id。
封装json的代码如下
//根据clientSocket.getOutputStream得到BufferedWriter对象,从而从输出流中获取数据
mWriter=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"utf-8"));
。。。。。
//封装成json
JSONObject json = new JSONObject();
json.put("to", Integer.parseInt(friendId));
json.put("msg", msgContent);
//通过BufferedWriter对象向服务器写数据
mWriter.write(json.toString()+"\n");
//一定要调用flush将缓存中的数据写到服务器
mWriter.flush();
这个json中包含三个信息:①消息到达方id②消息的内容③消息发送方的id。封装后通过BufferWriter的write方法将消息发送到服务器。
3.2 客户端接收消息的实现
这里接收消息是用了while循环不断的监听服务器是否有消息发送过来,如果有消息发送过来则用BufferedReader一行一行的去读取消息的内容,然后显示,实现的主要代码如下:
//根据clientSocket.getInputStream得到BufferedReader对象,从而从输入流中获取数据
mReader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"utf-8"));
//根据clientSocket.getOutputStream得到BufferedWriter对象,从而从输出流中获取数据
mWriter=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"utf-8"));
while(isReceivingMsgReady){
if(mReader.ready()){
Message msg = handler.obtainMessage();
msg.what=2;
msg.obj=mReader.readLine();
handler.sendMessage(msg);
}
Thread.sleep(200);
}
mWriter.close();
mReader.close();
clientSocket.close();
可以看到在客户端通过while循环当mReader.ready()为true时就会读取服务器返回消息的一行,然后更新显示。
4、实现两个手机间的通讯服务器的实现
服务器端的代码我使用是MyEclipse,首先我们来看看上述发送消息的过程中服务器端运行的截图:
服务器端的功能是怎么实现的呢?毫无疑问首先要做的当然是初始化服务器并指定端口号,代码如下:
serverSocket = new ServerSocket(SOCKET_PORT);
接着当有客户端连接到服务器时会为每一个客户端开启一个子线程,并将这个子线程加入到集合中对应的代码如下
while (flag) {
//有客户端连接,时serverSocket.accept()方法会返回客户端socket
Socket clientSocket = serverSocket.accept();
SocketThread socketThread = new SocketThread(clientSocket,socketId++);
socketThread.start();
mThreadList.add(socketThread);
}
在开启的子线程SocketThread中会有一个while循环监听客户端发过来的消息,并将这条消息添加到mThreadList集合,在这个子线程中循环读取客户端发过来的消息
//循环读取客户端发过来的消息
while (flag) {
if (reader.ready()) {
String comeData=reader.readLine();
JSONObject msgJson = new JSONObject(comeData);
Message msg = new Message();
msg.setTo(msgJson.getInt("to"));
msg.setMsg(msgJson.getString("msg"));
msg.setFrom(mSocketId);
msg.setTime(getTime(System.currentTimeMillis()));
mMsgList.add(msg);
System.out.println("用户:"+mSocketId+"向用户:"+msg.getTo()+"发送的消息内容为:"+msg.getMsg());
}
Thread.sleep(100);
}
其实也就是说在服务器中为每一个连接到服务器的客户端开启一个子线程,并在这个子线程中循环监听这个客户端是否发过来消息,在上面我们看到服务器解析消息后,将这条消息封装到了Message这个bean中并添加到了集合中。Message中包含的信息从上面可以看出。到这里服务器就可以收到服务器发过来的消息了,服务器收到消息后要做的工作就是将这条消息发送给客户端,(从实现原理图中可以看出服务器起到一个中转的作用)那么怎样实现这个功能呢?它的实现也不难,从上面的描述我们可以知道只要客户端向服务器发送一条消息,我们就会将这条消息放到一个集合mMsgList中,也就是说只要服务器收到消息mMsgList这个集合就不为空,只要mMsgList这个集合不为空就说明服务器还拥有未转发的消息,需要转发。怎么实现转发呢?
首先这里有两个集合一个是Message的集合mMsgList,另一个是为每一个客户端Socket开启的一个子线程SocketThread的集合mThreadList。这两个集合的关系是每一个Message肯定是mThreadList中的一个SocketThread(客户端)发送的。
当SocketThread的id与Messsage中的to(即消息的到达方)相等时,因为每一个客户端(假设是clientSocket1)连接到服务器时都要开启一个SocketThread子线程,在这个子线程中有clientSocket1的引用,所以当相等时就说明这个Message是发送给这个clientSocket1的。然后通过这个clientSocket1的BufferedWriter将这个消息发送给这个客户端。与其对应的代码如下
while(flag) {
if(mMsgList.size() > 0) {
Message from = mMsgList.get(0);
for(SocketThread toThread : mThreadList) {
//遍历mThreadList如果to.socketID==from.to说明这个toThread与mMsgList中的这条内容是对应的
//这里toThread的作用是通过它得到这条消息的BufferedWriter,mMsgList.get(0)得到这条消息,然后通过
//BufferedWriter将这条消息发送到指定方
if(toThread.mSocketId == from.getTo()) {
//这里的writer是SocketThread中的writer,这样才能保证在调用writer.flush之后消息到达
//我们的指定方
BufferedWriter writer = toThread.writer;
JSONObject json = new JSONObject();
json.put("from", from.getFrom());
json.put("msg", from.getMsg());
json.put("time", from.getTime());
writer.write(json.toString()+"\n");
writer.flush();
System.out.println("转发消息成功");
break;
}
}
mMsgList.remove(0);
}
Thread.sleep(200);
}
这样将这条消息解析封装成json后就发送到了指定的客户端,就完成了两个android机的通讯。其实个人觉着对这些原理的知识还是需要去好好学习,弄懂的,它的实现思想对我们以后的编程也是很有作用的。
关于实现两个手机端通讯的讨论就到这里了,可能我们看到的那些通讯的软件采用的方式不是本文使用的方式,但是原理性的东西是不会变的,这篇博客也是从最原始的地方来理解手机通讯的一些简单的原理。
如有谬误,欢迎批评指正,如有疑问欢迎留言。
如果本篇博客对你有帮助就点击左上角关注,关注吧,锁定本台观看更多精彩内容0.0
这里提醒大家注意的是源码包含两部分,一部分是服务端,另一部分是客户端,服务端是MyEclipse程序,客户端就是我们的android程序。
文章浏览阅读100次。该楼层疑似违规已被系统折叠隐藏此楼查看此楼程序在这个邮箱里,行列式的计算没有问题,好像问题出在了把行列式变换上,就是slove(1,n)这个函数的运算上,那位大神可以看看问题到底出在哪…… 不胜感激!!!#include #include void input(int n);void output(int n);double slove(int i , int n);double A[10][1..._c语言怎么列方程
文章浏览阅读426次,点赞17次,收藏9次。序列决策问题指代理需要连续地做一系列决策,以达到长期的目标。
文章浏览阅读1.5k次。Android平台自1.5版本之后开放了输入法框架(Input Method Framework,IMF),IMF是Android平台的特色设计。它的出现,为诞生不带实体键盘的设备提供了可能。同时,IMF开放了Android平台输入法的开发接口,为Android平台的输入法提供了可扩展性。OPhone平台继承了Android平台的输入法框架。本文首先介绍OPhone平台IMF的构成、工作机制和流程,以便广大开发者能够更好的理解OPhone平台是如何实现文字输入。接下来,将以一个简单的_选择一款你熟悉的输入法软件,提取功能点,谈谈你对输入法开发的认识
文章浏览阅读731次。2016-05-24 14:52:52 浏览量:991win7系统安装显卡后出现蓝屏问题怎么办呢?其实安装显卡后出现蓝屏也是比较常见的故障问题,网上也讲解很多关于win7系统安装显卡后出现蓝屏的资讯,可能是驱动不兼容显卡导致,如何解决呢?大家可以在win7系统开机时进入安全模式来设置与修复,轻松解决问题,下面来看看详细设置步骤吧。2017-06-23 09:51:30 浏览量:1728Win7..._华为服务器安装win7蓝屏
文章浏览阅读8k次,点赞67次,收藏82次。Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。本期文章将带你一气呵成,了解Redis安装与连接_redis连接
文章浏览阅读900次,点赞21次,收藏18次。本项目为参加分类考试的学生提供一个了解学校及专业的平台,以各个学校专业的信息和特点为基础,并让学生从自身的兴趣爱好出发,有效减少学生选择学校专业时的盲目性,让学生自主地选择适合自身的学校专业。在本项目的开发过程中,通过对项目的需求进行详细分析后,得到主要的功能模块,并对每一个功能模块进行细化。针对于参加分类招生考试的学生了解高职院校方式单一的现状,本项目为参加分类招生考试的学生提供一个了解学校、专业的平台,以及辅助学生了解自身喜好,搭建学生和学校间的桥梁,解决了分类考试中学生选择学校专业过程里的需求缺口。
文章浏览阅读649次。Kubernetes网络隔离Network Policies隔离手段:NetworkPolicy要在Kubernetes集群中使用NetworkPolicy,CNI网络插件必须维护一个NetworkPolicy Controller,支持Kubernetes 的NetworkPolicy。实现了NetworkPolicy的网络插件包括Weave和Calico等,但不包括Flannel。通过控制循环的方式对NetworkPolicy对象的增删改查作出响应,然后在宿主机上完成iptables规则的配置工作_serviceaccount/weave-net unchanged
文章浏览阅读1k次。RIL_UNSOL_PHYSICAL_CHANNEL_CONFIGPhysicalChannelConfig.javaLTE下radio log搜RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG,查看是否有以下字符串mConnectionStatus=SecondaryServing,mRat=20,有的话就是NSA_physicalchannelconfig.java
文章浏览阅读1k次。若依 apifox 自动登录_若依 自动登陆
文章浏览阅读207次。这题是挑战程序设计竞赛的例题,因为师兄讲了所以就补了做法:建图的方法是:加一个源点和汇点,讲饮料或食物分别连向源点、汇点,对于每一头牛,把它和它喜欢的食物和饮料连边,由于每一头牛在考虑的时候都是只能被一个边流入和流出(因为每一头牛都是只能吃一个食物喝一个饮料),所以把牛拆点(假如拆成牛1,牛2),就在牛1和牛2之间连一条边。然后源点到汇点跑一遍dinic就可以了。代码:#p..._3281dining 挑程
文章浏览阅读484次。四 HDFS 的数据流4.1 HDFS 写数据流程4.1.1 剖析文件写入 1)客户端通过 Distributed FileSystem 模块向 namenode 请求上传文件,namenode 检查目标文件是否已存在,父目录是否存在。2)namenode 返回是否可以上传。3)客户端请求第一个 block 上传到哪几个 datanode 服务器上。4)namenod..._pwd /opt/module/hadoop-2.7.2/data/tmp/dfs/name/current
文章浏览阅读8k次。<!DOCTYPE html><html><head> <style> div { width: 60px; height: 60px; margin: 10px; float: left; border: 2px solid blue;}.blue { background: blue;}.w..._用if编写点击div改变宽高颜色