package com.ccf.feige.net;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.Vector;
import java.util.concurrent.ConcurrentLinkedQueue;
import android.os.Message;
import android.util.Log;
import com.ccf.feige.activity.MyFeiGeActivity;
import com.ccf.feige.activity.MyFeiGeBaseActivity;
import com.ccf.feige.data.ChatMessage;
import com.ccf.feige.data.User;
import com.ccf.feige.interfaces.ReceiveMsgListener;
import com.ccf.feige.utils.IpMessageConst;
import com.ccf.feige.utils.IpMessageProtocol;
/**
* 飞鸽的网络通信辅助类
* 实现UDP通信以及UDP端口监听
* 端口监听采用多线程方式
*
* 单例模式
* @author ccf
*
* V1.0 2012/2/14,寂寞的情人节版本,嘿嘿
*
*/
public class NetThreadHelper implements Runnable{
public static final String TAG = "NetThreadHelper";
private static NetThreadHelper instance;
private static final int BUFFERLENGTH = 1024; //缓冲大小
private boolean onWork = false; //线程工作标识
private String selfName;
private String selfGroup;
private Thread udpThread = null; //接收UDP数据线程
private DatagramSocket udpSocket = null; //用于接收和发送udp数据的socket
private DatagramPacket udpSendPacket = null; //用于发送的udp数据包
private DatagramPacket udpResPacket = null; //用于接收的udp数据包
private byte[] resBuffer = new byte[BUFFERLENGTH]; //接收数据的缓存
private byte[] sendBuffer = null;
private Map<String,User> users; //当前所有用户的集合,以IP为KEY
private int userCount = 0; //用户个数。注意,此项值只有在调用getSimpleExpandableListAdapter()才会更新,目的是与adapter中用户个数保持一致
private Queue<ChatMessage> receiveMsgQueue; //消息队列,在没有聊天窗口时将接收的消息放到这个队列中
private Vector<ReceiveMsgListener> listeners; //ReceiveMsgListener容器,当一个聊天窗口打开时,将其加入。一定要记得适时将其移除
private NetThreadHelper(String name){
users = new HashMap<String, User>();
receiveMsgQueue = new ConcurrentLinkedQueue<ChatMessage>();
listeners = new Vector<ReceiveMsgListener>();
selfName = name;
selfGroup = "android";
}
public static NetThreadHelper newInstance(String name){
if(instance == null)
instance = new NetThreadHelper(name);
return instance;
}
public Map<String, User> getUsers(){
return users;
}
public int getUserCount(){
return userCount;
}
public Queue<ChatMessage> getReceiveMsgQueue(){
return receiveMsgQueue;
}
//添加listener到容器中
public void addReceiveMsgListener(ReceiveMsgListener listener){
if(!listeners.contains(listener)){
listeners.add(listener);
}
}
//从容器中移除相应listener
public void removeReceiveMsgListener(ReceiveMsgListener listener){
if(listeners.contains(listener)){
listeners.remove(listener);
}
}
/**
*
* 此方法用来判断是否有处于前台的聊天窗口对应的activity来接收收到的数据。
*/
private boolean receiveMsg(ChatMessage msg){
for(int i = 0; i < listeners.size(); i++){
ReceiveMsgListener listener = listeners.get(i);
if(listener.receive(msg)){
return true;
}
}
return false;
}
public void noticeOnline(){ // 发送上线广播
IpMessageProtocol ipmsgSend = new IpMessageProtocol();
ipmsgSend.setVersion(String.valueOf(IpMessageConst.VERSION));
ipmsgSend.setSenderName(selfName);
ipmsgSend.setSenderHost(selfGroup);
ipmsgSend.setCommandNo(IpMessageConst.IPMSG_BR_ENTRY); //上线命令
ipmsgSend.setAdditionalSection(selfName + "\0" ); //附加信息里加入用户名和分组信息
InetAddress broadcastAddr;
try {
broadcastAddr = InetAddress.getByName("255.255.255.255"); //广播地址
sendUdpData(ipmsgSend.getProtocolString()+"\0", broadcastAddr, IpMessageConst.PORT); //发送数据
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(TAG, "noticeOnline()....广播地址有误");
}
}
public void noticeOffline(){ //发送下线广播
IpMessageProtocol ipmsgSend = new IpMessageProtocol();
ipmsgSend.setVersion(String.valueOf(IpMessageConst.VERSION));
ipmsgSend.setSenderName(selfName);
ipmsgSend.setSenderHost(selfGroup);
ipmsgSend.setCommandNo(IpMessageConst.IPMSG_BR_EXIT); //下线命令
ipmsgSend.setAdditionalSection(selfName + "\0" + selfGroup); //附加信息里加入用户名和分组信息
InetAddress broadcastAddr;
try {
broadcastAddr = InetAddress.getByName("255.255.255.255"); //广播地址
sendUdpData(ipmsgSend.getProtocolString() + "\0", broadcastAddr, IpMessageConst.PORT); //发送数据
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(TAG, "noticeOnline()....广播地址有误");
}
}
public void refreshUsers(){ //刷新在线用户
users.clear(); //清空在线用户列表
noticeOnline(); //发送上线通知
MyFeiGeBaseActivity.sendEmptyMessage(IpMessageConst.IPMSG_BR_ENTRY);
}
@Override
public void run() {
// TODO Auto-generated method stub
while(onWork){
try {
udpSocket.receive(udpResPacket);
} catch (IOException e) {
// TODO Auto-generated catch block
onWork = false;
if(udpResPacket != null){
udpResPacket = null;
}
if(udpSocket != null){
udpSocket.close();
udpSocket = null;
}
udpThread = null;
Log.e(TAG, "UDP数据包接收失败!线程停止");
break;
}
if(udpResPacket.getLength() == 0){
Log.i(TAG, "无法接收UDP数据或者接收到的UDP数据为空");
continue;
}
String ipmsgStr = "";
try {
ipmsgStr = new String(resBuffer, 0, udpResPacket.getLength(),"gbk");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(TAG, "接收数据时,系统不支持GBK编码");
}//截取收到的数据
Log.i(TAG, "接收到的UDP数据内容为:" + ipmsgStr);
IpMessageProtocol ipmsgPro = new IpMessageProtocol(ipmsgStr); //
int commandNo = ipmsgPro.getCommandNo();
int commandNo2 = 0x000000FF & commandNo; //获取命令字
switch(commandNo2){
case IpMessageConst.IPMSG_BR_ENTRY: { //收到上线数据包,添加用户,并回送IPMSG_ANSENTRY应答。
addUser(ipmsgPro); //添加用户
MyFeiGeBaseActivity.sendEmptyMessage(IpMessageConst.IPMSG_BR_ENTRY);
//下面构造回送报文内容
IpMessageProtocol ipmsgSend = new IpMessageProtocol();
ipmsgSend.setVersion(String.valueOf(IpMessageConst.VERSION));
ipmsgSend.setSenderName(selfName);
ipmsgSend.setSenderHost(selfGroup);
ipmsgSend.setCommandNo(IpMessageConst.IPMSG_ANSENTRY); //回送报文命令
ipmsgSend.setAdditionalSection(selfName + "\0" ); //附加信息里加入用户名和分组信息
sendUdpData(ipmsgSend.getProtocolString(), udpResPacket.getAddress(), udpResPacket.getPort()); //发送数据
}
break;
case IpMessageConst.IPMSG_ANSENTRY: { //收到上线应答,更新在线用户列表
addUser(ipmsgPro);
MyFeiGeBaseActivity.sendEmptyMessage(IpMessageConst.IPMSG_ANSENTRY);
}
break;
case IpMessageConst.IPMSG_BR_EXIT:{ //收到下线广播,删除users中对应的值
String userIp = udpResPacket.getAddress().getHostAddress();
users.remove(userIp);
MyFeiGeBaseActivity.sendEmptyMessage(IpMessageConst.IPMSG_BR_EXIT);
Log.i(TAG, "根据下线报文成功删除ip为" + userIp + "的用户");
}
break;
case IpMessageConst.IPMSG_SENDMSG:{ //收到消息,处理
String senderIp = udpResPacket.getAddress().getHostAddress(); //得到发送者IP
String senderName = ipmsgPro.getSenderName(); //得到发送者的名称
String additionStr = ipmsgPro.getAdditionalSection(); //得到附加信息
Date time = new Date(); //收到信息的时间
String msgTemp; //直
评论3
最新资源