[置顶] android socket 聊天实现与调试
网上很多基于Socket的聊天实现都是不完整的。。。
结合自己的经验给大家分享一下,完整代码可以在GitHub里获取https://github.com/zz7zz7zz/android-socket-client
1.废话不多说,附主要的Client类
package com.boyaa.push.lib.service; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue; import android.content.Context;
import android.util.Log; import com.boyaa.push.lib.util.NetworkUtil; /**
*
* @author Administrator
*
*/
public class Client { private final int STATE_OPEN=1;//socket打开
private final int STATE_CLOSE=1<<1;//socket关闭
private final int STATE_CONNECT_START=1<<2;//开始连接server
private final int STATE_CONNECT_SUCCESS=1<<3;//连接成功
private final int STATE_CONNECT_FAILED=1<<4;//连接失败
private final int STATE_CONNECT_WAIT=1<<5;//等待连接 private String IP="192.168.1.100";
private int PORT=60000; private int state=STATE_CONNECT_START; private Socket socket=null;
private OutputStream outStream=null;
private InputStream inStream=null; private Thread conn=null;
private Thread send=null;
private Thread rec=null; private Context context;
private ISocketResponse respListener;
private LinkedBlockingQueue<Packet> requestQueen=new LinkedBlockingQueue<Packet>();
private final Object lock=new Object(); public int send(Packet in)
{
requestQueen.add(in);
synchronized (lock)
{
lock.notifyAll();
}
return in.getId();
} public void cancel(int reqId)
{
Iterator<Packet> mIterator=requestQueen.iterator();
while (mIterator.hasNext())
{
Packet packet=mIterator.next();
if(packet.getId()==reqId)
{
mIterator.remove();
}
}
} public Client(Context context,ISocketResponse respListener)
{
this.context=context;
this.respListener=respListener;
} public boolean isNeedConn()
{
return !((state==STATE_CONNECT_SUCCESS)&&(null!=send&&send.isAlive())&&(null!=rec&&rec.isAlive()));
} public void open()
{
reconn();
} public void open(String host,int port)
{
this.IP=host;
this.PORT=port;
reconn();
} private long lastConnTime=0;
public synchronized void reconn()
{
if(System.currentTimeMillis()-lastConnTime<2000)
{
return;
}
lastConnTime=System.currentTimeMillis(); close();
state=STATE_OPEN;
conn=new Thread(new Conn());
conn.start();
} public synchronized void close()
{
if(state!=STATE_CLOSE)
{
try {
if(null!=socket)
{
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
socket=null;
} try {
if(null!=outStream)
{
outStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
outStream=null;
} try {
if(null!=inStream)
{
inStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
inStream=null;
} try {
if(null!=conn&&conn.isAlive())
{
conn.interrupt();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
conn=null;
} try {
if(null!=send&&send.isAlive())
{
send.interrupt();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
send=null;
} try {
if(null!=rec&&rec.isAlive())
{
rec.interrupt();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
rec=null;
} state=STATE_CLOSE;
}
requestQueen.clear();
} private class Conn implements Runnable
{
public void run() {
while(state!=STATE_CLOSE)
{
try {
state=STATE_CONNECT_START;
socket=new Socket();
socket.connect(new InetSocketAddress(IP, PORT), 15*1000);
state=STATE_CONNECT_SUCCESS;
} catch (Exception e) {
e.printStackTrace();
state=STATE_CONNECT_FAILED;
} if(state==STATE_CONNECT_SUCCESS)
{
try {
outStream=socket.getOutputStream();
inStream=socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
} send=new Thread(new Send());
rec=new Thread(new Rec());
send.start();
rec.start();
break;
}
else
{
state=STATE_CONNECT_WAIT;
//如果有网络没有连接上,则定时取连接,没有网络则直接退出
if(NetworkUtil.isNetworkAvailable(context))
{
try {
Thread.sleep(15*1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
else
{
break;
}
}
}
}
} private class Send implements Runnable
{
public void run() {
try {
while(state!=STATE_CLOSE&&state==STATE_CONNECT_SUCCESS&&null!=outStream)
{
Packet item;
while(null!=(item=requestQueen.poll()))
{
outStream.write(item.getPacket());
outStream.flush();
item=null;
} synchronized (lock)
{
lock.wait();
}
}
}catch(SocketException e1)
{
e1.printStackTrace();//发送的时候出现异常,说明socket被关闭了(服务器关闭)java.net.SocketException: sendto failed: EPIPE (Broken pipe)
reconn();
}
catch (Exception e) {
e.printStackTrace();
}
}
} private class Rec implements Runnable
{
public void run() { try {
while(state!=STATE_CLOSE&&state==STATE_CONNECT_SUCCESS&&null!=inStream)
{
byte[] bodyBytes=new byte[5];
int offset=0;
int length=5;
int read=0; while((read=inStream.read(bodyBytes, offset, length))>0)
{
if(length-read==0)
{
if(null!=respListener)
{
respListener.onSocketResponse(new String(bodyBytes));
} offset=0;
length=5;
read=0;
continue;
}
offset+=read;
length=5-offset;
} reconn();//走到这一步,说明服务器socket断了
break;
}
}
catch(SocketException e1)
{
e1.printStackTrace();//客户端主动socket.close()会调用这里 java.net.SocketException: Socket closed
}
catch (Exception e2) {
e2.printStackTrace();
} }
}
}
2.使用SocketTool工具进行调试
a.创建Server.点击TCP Server ,点击创建,输入端口号,点击确定(同时要点击启动监听)。
b.在android客户端输入IP和端口,点击打开或者重连,socketTool便可以看见你连上的Client了
c.在客户端输入要发送的文字,点击发送,在socketTool便可以看到你往server里发送的数据了,
在socketTool里输入要往客户端发送的内容,点击发送,便可在手机客户端里看到Server往client发送的数据了
这样就可以Client-Server之间进行数据对发了。
邮箱:zz7zz7zz@163.com
微博:http://weibo.com/u/3209971935
[置顶] android socket 聊天实现与调试的更多相关文章
- [置顶] Android开发笔记(成长轨迹)
分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API ...
- [置顶] Android系统移植与调试之------->Amlogic方案编译步骤
1. 拷贝Amlogic的SourceCode 切换目录到 /home/roco/work/amlogic/SourceCode/mx0831-0525下将mx0831-0525.tgz拷贝到 / ...
- [置顶] Android系统移植与调试之------->如何修改Android设备状态条上音量加减键在横竖屏的时候的切换与显示
这两天由于一个客户的要求,将MID竖屏时候的状态条上的音量键去掉.所以尝试修改了一下,成功了,分享一下经验. 先看一下修改后的效果图,如下所示 . 横屏的时候:有音量加减键 竖屏的时候:音量加减键被去 ...
- [置顶] Android系统移植与调试之------->build.prop文件详细赏析
小知识:什么是build.prop? /system/build.prop 是一个属性文件,在Android系统中.prop文件很重要,记录了系统的设置和改变,类似於/etc中的文件.这个文件是如 ...
- [置顶] Android系统移植与调试之------->如何修改Android设备添加3G上网功能
1.首先先来看一下修改前后的效果对比图 step1.插上3G设备前 step2.插上3G设备后,获取信号中.... step3.插上3G设备后,获取到信号 step4.使用3G信号浏览网页 2.下面讲 ...
- [置顶] Android JNI必须掌握的五点
1:JNI是什么? Java NativeInterface(JNI)是Java提供的一个很重要的特性.它使得用诸如C/C++等语言编写的代码可以与运行于Java虚拟机(JVM)中的 Java代码 ...
- [置顶] Android中使用Movie显示gif动态图
转载请注明: http://blog.csdn.net/u012975705/article/details/48717391 在看这篇博文之前对attr自定义属性还是不是很熟的童鞋可以先看看:An ...
- Android Socket 聊天室示例
服务端: package com.test.chatServer; import java.io.IOException; import java.net.ServerSocket; import j ...
- [置顶] Android AlarmManager实现不间断轮询服务
在消息的获取上是选择轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了.但如果只是一般的消息检测比如更新检查,可能是半个小时或一个小时一 ...
随机推荐
- 学习mysql replication
- MVC js动态生成from提交数据然后生成文件下载
前台: 点击触发下面事件 var turnForm = document.createElement("form"); //一定要加入到body中!! document.body. ...
- 【译】EntityFramework6与EntityFrameworkCore的区别
EntityFramework6 EF6 是一个久经考验的数据库访问技术,发展多年,拥有许多特性,并且成熟稳定.2008年EF作为 .Net 3.5 Sp1 和Visual Studio 2008 S ...
- 最完整的PS快捷键大全(绝对经典)
快速恢复默认值 有些不擅长Photoshop的朋友为了调整出满意的效果真是几经周折,结果发现还是原来的默认效果最好,这下傻了眼,后悔不该当初呀!怎么恢复到默认值呀?试着轻轻点按选项栏上的工具图标,然后 ...
- Go语言规格说明书 之 词汇元素(Lexical elements)
go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,完整的介绍Go语 ...
- 从零开始自己搭建复杂网络(以Tensorflow为例)
从零开始自己搭建复杂网络(以MobileNetV2为例) tensorflow经过这几年的发展,已经成长为最大的神经网络框架.而mobileNetV2在经过Xception的实践与深度可分离卷积的应用 ...
- opencv SVM多分类 人脸识别
上一篇介绍了OPENCV中SVM的简单使用,以及自带的一个二分类问题. 例子中的标签是程序手动写的,输入也是手动加的二维坐标点. 对于复杂问题就必须使用数据集中的图片进行训练,标签使用TXT文件或程序 ...
- HDU 2512 一卡通大冒险(第二类斯特林数+贝尔数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2512 题目大意:因为长期钻研算法, 无暇顾及个人问题,BUAA ACM/ICPC 训练小组的帅哥们大部 ...
- 一步一步学习IdentityServer3 (2)
下面就来做一个例子:IdentityServer3服务端的配置 VS2015创建一个MVC项目 IdrOAuth 用来授权的认证的站点
- docker:一个支持django的dockerfile
其中,包括了主要的生产环境模块, 从alpine作起,镜像不大.保存用. FROM alpine:3.7 COPY . /target-dir WORKDIR /target-dir RUN sed ...