[置顶] 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实现不间断轮询服务
在消息的获取上是选择轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了.但如果只是一般的消息检测比如更新检查,可能是半个小时或一个小时一 ...
随机推荐
- C#使用WSDL服务总结
站在巨人肩上才能看的更远! 1.C# 利用VS自带的WSDL工具生成WebService服务类 2.C#使用WSDL服务
- poj2056
寻找向左凸的地方,每个左凸能让S数量-2.上边或下边如果是半个左凸的话则各对应-1 #include <cstdio> #include <cstring> #include ...
- [原创]Python/Django使用富文本编辑器XHeditor上传本地图片
前言 为了在Django框架下使用Xheditor上传图片,居然折腾了我一个晚上.期间也遇到种种问题,网上相关资料极少.现在把经验分享给大家. 正文 xheditor篇 1.下载http://xhed ...
- HTML5 drawImage性能问题
最近做游戏发现,为了节省HTTP请求,把很多组动画放到了一张图片上,也就是传说中的雪碧图,但是用drawImage从图片上截取一部分绘制在canvas上时会非常慢. 我的图片尺寸为5000*7000 ...
- Ibatis.Net 执行存储过程学习(八)
首先在数据库创建存储过程: create proc [dbo].[usp_GetPersonById] @Id int as begin select Id,Name from Person wher ...
- mac OS配置用户全局环境变量(设置字符集为UTF8)
mac OS系统跟linux系统一样也是将用户的全局环境变量保存在.bash_profile配置文件中,只是mac OS默认没有此文件. 1.创建.bash_profile文件 vi ~/.bash_ ...
- Java abstract 关键字
abstract是声明抽象类和抽象方法的关键字 包含抽象方法的类叫抽象类,如果一个类中包含一个或多个抽象方法,该类必须被限定为抽象的,否则编译器会报错,抽象类不可创建对象,创建抽象类的对象编译器会报错 ...
- TinyHttpd代码解析
十一假期,闲来无事.看了几个C语言开源代码.http://www.cnblogs.com/TinyHttpd 这里本来想解析一下TinyHttpd的代码,但是在网上一搜,发现前辈们已经做的很好了.这里 ...
- C++学习笔记(原创)
以下内容为自己一年多的C++学习心得,纯原创,转载请注明源地址. 一年多的C++学习过程中,自己阅读了很多C++经典著作,有<effective c++>,<more effecti ...
- django 实现文件下载功能
一.概述 在实际的项目中很多时候需要用到下载功能,如导excel.pdf或者文件下载,当然你可以使用web服务自己搭建可以用于下载的资源服务器,如nginx,这里我们主要介绍django中的文件下载. ...