?? resender.java
字號:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.tsinghua.lumaqq.qq.net;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.packets.InPacket;
import edu.tsinghua.lumaqq.qq.packets.OutPacket;
/**
* 這個線程執(zhí)行重發(fā)任務(wù)
*
* @author 馬若劼
*/
public class Resender extends Thread {
// Log對象
protected static Log log = LogFactory.getLog(Resender.class);
// QQ客戶端類
private QQClient client;
// 停止標(biāo)志
private volatile boolean stop;
// 檢查應(yīng)答包是否到達的類
private PacketMonitor monitor;
// 超時隊列
private LinkedList timeoutQueue;
// 包 to Port的映射
private Map toPort;
// temp variable
private String portName;
/**
* 創(chuàng)建一個重發(fā)線程
*
* @param client
* QQClient
*/
public Resender(QQClient client) {
this.client = client;
stop = false;
monitor = PacketMonitor.getInstance();
timeoutQueue = new LinkedList();
toPort = new HashMap();
setName("Resender");
setDaemon(true);
}
/**
* 添加一個包到超時隊列
*
* @param packet
* 發(fā)送包對象
* @param name
* port名稱
*/
public synchronized void add(OutPacket packet, String name) {
timeoutQueue.addLast(packet);
toPort.put(packet, name);
}
/**
* 得到超時隊列的第一個包,不把它從隊列中刪除
* @return 超時隊列的第一個包,如果沒有,返回null
*/
public synchronized OutPacket get() {
if(timeoutQueue.size() == 0) return null;
return (OutPacket)timeoutQueue.getFirst();
}
/**
* 得到超時隊列的第一個包,并把它從隊列中刪除
* @return 超時隊列的第一個包,如果沒有,返回null
*/
public synchronized OutPacket remove() {
if(timeoutQueue.size() == 0)
return null;
else {
OutPacket ret = (OutPacket)timeoutQueue.removeFirst();
portName = (String)toPort.remove(ret);
return ret;
}
}
/**
* 刪除ack對應(yīng)的請求包
* @param ack
*/
public synchronized void remove(InPacket ack) {
int hash = ack.hashCode();
int size = timeoutQueue.size();
for(int i = 0; i < size; i++) {
OutPacket packet = (OutPacket)timeoutQueue.get(i);
if(packet.hashCode() == hash) {
toPort.remove(timeoutQueue.remove(i));
break;
}
}
}
/**
* 得到下一個包的超時時間
* @return 下一個包的超時時間,如果隊列為空,返回一個固定值
*/
private long getTimeoutLeft() {
OutPacket packet = get();
if(packet == null)
return QQ.QQ_SENDQUEUE_TIMEOUT;
else
return packet.getTimeout() - System.currentTimeMillis();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
log.debug("重發(fā)線程已經(jīng)啟動");
OutPacket packet = null;
while(!isStop()) {
synchronized(this) {
long t = getTimeoutLeft();
while(t > 0) {
// 等待t時間,然后再去查看是否有了包
try {
this.wait(t);
} catch (InterruptedException e) {
// 沒有什么要做的
}
// 如果停止標(biāo)志為true,跳出
if(stop) break;
t = getTimeoutLeft();
}
}
if(isStop()) break;
packet = remove();
// 發(fā)送
if(packet != null && !monitor.check(packet, false)) {
if(packet.needResend()) {
// 重發(fā)次數(shù)未到最大,重發(fā)
client.sendPacketAnyway(packet, portName);
} else {
// 觸發(fā)操作超時事件
fireOperationTimeOutEvent(packet);
}
}
}
log.debug("重發(fā)線程正常退出");
}
/**
* @param stop The stop to set.
*/
public synchronized void setStop(boolean stop) {
this.stop = stop;
this.notify();
}
/**
* 觸發(fā)超時事件
* @param p
*/
private void fireOperationTimeOutEvent(OutPacket packet) {
switch(packet.getHeader()) {
case QQ.QQ_HEADER_BASIC_FAMILY:
fireBasicFamilyTimeOutEvent(packet);
break;
case QQ.QQ_HEADER_05_FAMILY:
fire05FamilyTimeOutEvent(packet);
break;
}
}
/**
* @param packet
*/
private void fire05FamilyTimeOutEvent(OutPacket packet) {
QQEvent e = null;
switch(packet.getCommand()) {
case QQ.QQ_05_CMD_REQUEST_AGENT:
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_05_CMD_REQUEST_AGENT;
break;
case QQ.QQ_05_CMD_REQUEST_BEGIN:
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_05_CMD_REQUEST_BEGIN;
break;
case QQ.QQ_05_CMD_REQUEST_FACE:
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_05_CMD_REQUEST_FACE;
break;
case QQ.QQ_05_CMD_TRANSFER:
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_05_CMD_TRANSFER;
break;
}
// 觸發(fā)事件
if(e != null)
client.fireQQEvent(e);
}
/**
* @param packet
*/
private void fireBasicFamilyTimeOutEvent(OutPacket packet) {
QQEvent e = null;
switch(packet.getCommand()) {
case QQ.QQ_CMD_REQUEST_LOGIN_TOKEN:
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_REQUEST_LOGIN_TOKEN;
break;
case QQ.QQ_CMD_SEND_IM:
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_SEND_IM;
break;
case QQ.QQ_CMD_KEEP_ALIVE:
// 說明連接已經(jīng)丟失
e = new QQEvent(packet);
e.type = QQEvent.QQ_CONNECTION_LOST;
break;
case QQ.QQ_CMD_LOGIN:
// 這種情況說明登陸超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_LOGIN;
break;
case QQ.QQ_CMD_GET_USER_INFO:
// 用戶更新好友信息超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_GET_USER_INFO;
break;
case QQ.QQ_CMD_MODIFY_INFO:
// 更新自己的信息的超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_MODIFY_INFO;
break;
case QQ.QQ_CMD_DELETE_FRIEND:
// 刪除好友超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_DELETE_FRIEND;
break;
case QQ.QQ_CMD_ADD_FRIEND:
// 添加好友超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_ADD_FRIEND;
break;
case QQ.QQ_CMD_ADD_FRIEND_AUTH:
// 發(fā)送認(rèn)證信息超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_ADD_FRIEND_AUTH;
break;
case QQ.QQ_CMD_GET_FRIEND_LIST:
// 得到好友列表超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_GET_FRIEND_LIST;
break;
case QQ.QQ_CMD_GET_FRIEND_ONLINE:
// 得到好友在線列表超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_GET_FRIEND_ONLINE;
break;
case QQ.QQ_CMD_REMOVE_SELF:
// 刪除自己失敗
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_REMOVE_SELF;
break;
case QQ.QQ_CMD_SEARCH_USER:
// 搜索在線用戶超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_SEARCH_USER;
break;
case QQ.QQ_CMD_ADVANCED_SEARCH:
// 高級搜索超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_ADVANCED_SEARCH;
break;
case QQ.QQ_CMD_GROUP_DATA_OP:
// 上傳分組名稱超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_GROUP_DATA_OP;
break;
case QQ.QQ_CMD_UPLOAD_GROUP_FRIEND:
// 上傳分組名稱超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_UPLOAD_GROUP_FRIEND;
break;
case QQ.QQ_CMD_DOWNLOAD_GROUP_FRIEND:
// 上傳分組名稱超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_DOWNLOAD_GROUP_FRIEND;
break;
case QQ.QQ_CMD_FRIEND_DATA_OP:
// 好友備注信息操作超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_FRIEND_DATA_OP;
break;
case QQ.QQ_CMD_CLUSTER_CMD:
// 群操作超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_CLUSTER_CMD;
break;
case QQ.QQ_CMD_SEND_SMS:
// 發(fā)送短消息超時
e = new QQEvent(packet);
e.type = QQEvent.QQ_OPERATION_TIMEOUT;
e.operation = QQ.QQ_CMD_SEND_SMS;
break;
}
// 觸發(fā)事件
if(e != null)
client.fireQQEvent(e);
}
/**
* @return Returns the stop.
*/
public synchronized boolean isStop() {
return stop;
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -