网上很多基于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. spring的事务控制

    1.事务介绍 (1)特性:ACID Atomicity(原子性):事务中的所有操作要么全做要么全不做 Consistency(一致性):事务执行的结果使得数据库从一个一致性状态转移到另一个一致性状态 ...

  2. Virut.ce-感染型病毒分析报告

    1.样本概况 病毒名称 Virus.Win32.Virut.ce MD5 6A500B42FC27CC5546079138370C492F 文件大小 131 KB (134,144 字节) 壳信息 无 ...

  3. 设置文字小于12px

    问题:有时候会需要设置一些小于12px的字或是icon: 方法:使用css3的transform的scale,来放大和缩小,但是相应的容器也会缩小 transform: scale(0.6);

  4. 设计模式及Python实现

    设计模式是什么? Christopher Alexander:“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样你就能一次又一次地使用该方案而不必做重复劳动.” 设计 ...

  5. Coursera台大机器学习技法课程笔记13-Deep Learning

    深度学习面临的问题和现在解决的办法: 简要来说,分两步使用DL:初始化时一层一层的选择权重,而后再进行训练: 那么怎么做pre-training,即怎么选择权重呢?好的权重能够不改变原有资料的信息,即 ...

  6. IdentityServer4使用EFCore生成MySql时的小bug

    EFCore生成PersistedGrantDbContextModelSnapshot的时候发现 b.Property<string>("Data") .IsRequ ...

  7. html屏幕旋转事件监听

    近期做微信服务号开发,在做图片展示的时候需要横竖屏的检测实现图片大小不同的展示. 添加屏幕旋转事件侦听,可随时发现屏幕旋转状态(左旋.右旋还是没旋). 摘自:http://bbs.phonegap10 ...

  8. 【Java】 大话数据结构(6) 栈的顺序与链式存储

    本文根据<大话数据结构>一书,实现了Java版的栈的顺序存储结构.两栈共享空间.栈的链式存储机构. 栈:限定仅在表尾进行插入和删除操作的线性表. 栈的插入(进栈)和删除(出栈)操作如下图所 ...

  9. 008 jquery过滤选择器-----------(子元素过滤选择器)

    1.介紹 2.程序 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  10. CSS transform中的rotate的旋转中心怎么设置

    transform-origin属性 默认情况,变形的原点在元素的中心点,或者是元素X轴和Y轴的50%处.我们没有使用transform-origin改变元素原点位置的情况下,CSS变形进行的旋转.移 ...