网上很多基于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 聊天实现与调试的更多相关文章

  1. [置顶] Android开发笔记(成长轨迹)

    分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API ...

  2. [置顶] Android系统移植与调试之------->Amlogic方案编译步骤

    1. 拷贝Amlogic的SourceCode 切换目录到  /home/roco/work/amlogic/SourceCode/mx0831-0525下将mx0831-0525.tgz拷贝到  / ...

  3. [置顶] Android系统移植与调试之------->如何修改Android设备状态条上音量加减键在横竖屏的时候的切换与显示

    这两天由于一个客户的要求,将MID竖屏时候的状态条上的音量键去掉.所以尝试修改了一下,成功了,分享一下经验. 先看一下修改后的效果图,如下所示 . 横屏的时候:有音量加减键 竖屏的时候:音量加减键被去 ...

  4. [置顶] Android系统移植与调试之------->build.prop文件详细赏析

    小知识:什么是build.prop?   /system/build.prop 是一个属性文件,在Android系统中.prop文件很重要,记录了系统的设置和改变,类似於/etc中的文件.这个文件是如 ...

  5. [置顶] Android系统移植与调试之------->如何修改Android设备添加3G上网功能

    1.首先先来看一下修改前后的效果对比图 step1.插上3G设备前 step2.插上3G设备后,获取信号中.... step3.插上3G设备后,获取到信号 step4.使用3G信号浏览网页 2.下面讲 ...

  6. [置顶] Android JNI必须掌握的五点

      1:JNI是什么? Java NativeInterface(JNI)是Java提供的一个很重要的特性.它使得用诸如C/C++等语言编写的代码可以与运行于Java虚拟机(JVM)中的 Java代码 ...

  7. [置顶] Android中使用Movie显示gif动态图

    转载请注明:  http://blog.csdn.net/u012975705/article/details/48717391 在看这篇博文之前对attr自定义属性还是不是很熟的童鞋可以先看看:An ...

  8. Android Socket 聊天室示例

    服务端: package com.test.chatServer; import java.io.IOException; import java.net.ServerSocket; import j ...

  9. [置顶] Android AlarmManager实现不间断轮询服务

    在消息的获取上是选择轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了.但如果只是一般的消息检测比如更新检查,可能是半个小时或一个小时一 ...

随机推荐

  1. Spark笔记之累加器(Accumulator)

    一.累加器简介 在Spark中如果想在Task计算的时候统计某些事件的数量,使用filter/reduce也可以,但是使用累加器是一种更方便的方式,累加器一个比较经典的应用场景是用来在Spark St ...

  2. centos-7安装redis服务

    一.Redis下载 在centOS里通过wget下载redis wget http://download.redis.io/releases/redis-4.0.11.tar.gz  具体版本下载地址 ...

  3. Tomcat优化步骤【转】

    一.Tomcat的缺省是多少,怎么修改 Tomcat的缺省端口号是8080.修改Tomcat端口号:1.找到Tomcat目录下的conf文件夹2.进入conf文件夹里面找到server.xml文件3. ...

  4. Springboot分模块开发详解(2):建立子工程

    1.创建base-entity 选中base工程,右键创建一个新的maven工程 自动选择了base这个目录存放子工程 创建后,pom.xml修改成如下内容: <?xml version=&qu ...

  5. python 列表元组加减乘除法

    元组(typle)列表(list)没有减法和除法,但有加法和乘法. 1.加法,即把元素相加.只可以list和tuple相加,不能加其他类型. t= (1, ) + (2, 3, 4) print(t, ...

  6. 测试开发之Django——No2.Django的安装以及项目创建

    开发平台:Mac Python版本:3.7 Django版本:2.0.5 一.Django的安装 1.pip安装 输入命令pip install Django==2.0.5 说明:不指定版本,则安装的 ...

  7. JAVA随笔(一)

    数组变量是数组的管理者,而不是拥有者.数组变量的比较,是判断它们是否管理同一个数组.将一个数组变量赋值给 另一个数组变量并不产生新的数组.想产生新的数组只能通过new来完成. 同样,String类型的 ...

  8. mysql 用init-connect+binlog实现用户操作追踪做access的ip的log记录

    在MYSQL中,每个连接都会先执行init-connect,进行连接的初始化.我们可以在这里获取用户的登录名称和thread的ID值.然后配合binlog,就可以追踪到每个操作语句的操作时间,操作人等 ...

  9. Laravel 的 JSON API 接口自动化测试

    Laravel 自带了两种测试类型 Feature Test: 功能测试.针对类似接口这种流程性的测试. Unit Test: 单元测试.针对单个函数这种输入输出结果的测试. 新建一个 Feature ...

  10. MFC命名规范

    属性部分 全局变量:g_ 常量:c_ c++类成员变量:m_ 静态变量:s_ 类型部分 指针:p 函数:fn 无效:v 句柄:h 长整型:l 布尔:b 浮点型(有时也指文件):f 双字:dw 字符串: ...