Azureus源码剖析(三)

本文详细解析了Azureus种子文件监听服务器的工作流程和技术实现,包括服务器监听端口的设置、守护线程处理客户端请求的过程以及如何根据核心组件的状态决定是否立即处理种子文件。

接着第一篇的工作,本篇继续分析种子文件监听服务器的实现细节。

先简单描述下其工作流程,首先服务器在6880端口处开启一个套接字监听,然后开启一个守护线程用于处理到来的“打开种子文件列表”请求,在这个服务线程中不断循环读取来自客户的请求,对torrent文件列表进行解析。如果此时Azureus的各个组件都已经创建完毕,则说明Azureus的核心处理组件可用,则直接对torrent文件列表进行处理,否则,先将torrent文件列表加入种子文件队列中,等到各个组件创建完毕后再来处理种子队列中的各个种子文件。

下面来查看其源代码,先看其成员变量:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> private ServerSocketsocket; // 服务器套接字
private int state; // 服务器当前状态
private boolean bContinue; // 服务线程是否继续运行
public static final int STATE_FAULTY = 0 ; // 错误状态
public static final int STATE_LISTENING = 1 ; // 监听状态
protected Listqueued_torrents = new ArrayList(); // 待解析种子文件队列,这里并没有考虑同步互斥的问题
protected boolean core_started = false ; // 核心处理组件是否已经启动

在其构造函数中完成服务器的创建和启动:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> socket = new ServerSocket( 6880 , 50 ,InetAddress.getByName( " 127.0.0.1 " )); // NOLAR:onlybindtolocalhost

state
= STATE_LISTENING; // 设置服务器状态为“监听”

而在pollForConnections中为Azureus添加了一个生命周期监听器,这样当其所有组件完成时就会通知此监听器,而后者会调用openQueuedTorrents方法,对待解析种子文件队列中排队的种子文件进行处理,此外,这个方法中还创建了一个守护线程用于处理到来的打开种子文件列表请求,实际的处理工作在pollForConnectionsSupport方法中完成:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> public void pollForConnections( final AzureusCoreazureus_core)
{
// 增加生命周期监听者
azureus_core.addLifecycleListener( new AzureusCoreLifecycleAdapter()
{
// 所有组件创建完毕
public void componentCreated(AzureusCorecore,AzureusCoreComponentcomponent)
{
if (component instanceof UIFunctionsSWT)
{
openQueuedTorrents(azureus_core);
// 打开排队的种子文件列表
}
}
});

if (socket != null )
{
// 开启一个守护线程用于处理到来的打开种子文件列表请求
Threadt = new AEThread( " StartServer " )
{
// runSupport是一个abstract方法,在run中调用,是实际的线程函数
public void runSupport()
{
pollForConnectionsSupport(azureus_core);
}
};
t.setDaemon(
true );
t.start();
// 启动线程
}
}

这里线程的中断采用设置运行标志的方式,我觉得这并不是一个很好的解决方案,因为若线程要完成的工作十分耗时,则线程的中断就不能立即见效。更好的办法应该是interrupt方法和中断标志混合起来使用。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> private void pollForConnectionsSupport(AzureusCoreazureus_core)
{
bContinue
= true ;
while (bContinue)
{
BufferedReaderbr
= null ;
try
{
Socketsck
= socket.accept(); // 接受一个连接请求
Stringaddress = sck.getInetAddress().getHostAddress(); // 绑定的本地IP地址
if (address.equals( " localhost " ) || address.equals( " 127.0.0.1 " ))
{
br
= new BufferedReader( new InputStreamReader(sck.getInputStream(),Constants.DEFAULT_ENCODING));
Stringline
= br.readLine(); // 读取一行数据
if (Logger.isEnabled())
Logger.log(
new LogEvent(LOGID, " Main::startServer:received' " + line + " ' " ));
if (line != null )
{
String[]args
= parseArgs(line); // 解析请求数据
if (args != null && args.length > 0 )
{
Stringdebug_str
= args[ 0 ]; // 第一行数据仅供测试使用,故抛弃不用
for ( int i = 1 ;i < args.length;i ++ )
{
debug_str
+= " ; " + args[i];
}
Logger.log(
new LogEvent(LOGID, " Main::startServer:decodedto' " + debug_str + " ' " ));
processArgs(azureus_core,args);
// 处理解析出的种子文件列表

}
}
}
sck.close();
}
catch (Exceptione)
{
if ( ! (e instanceof SocketException))
Debug.printStackTrace(e);
}
finally
{
try
{
if (br != null )
br.close();
}
catch (Exceptione){ /* ignore */ }
}
}
}

在种子文件列表解析成功后,对其处理要分情况考虑,若处理核心还未启动,则将其加入种子队列中排队等待,否则直接对其解析处理。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> try
{
this_mon.enter();

if ( ! core_started)
{
// 若核心还未启动,则进入种子队列中等待
queued_torrents.add( new Object[]{file_name, new Boolean(open)}); // 加入种子文件队列中
queued = true ;
}
}
finally
{
this_mon.exit();
}
if ( ! queued)
{
// 无须排队,直接进行种子文件的解析处理
handleFile(azureus_core,file_name,open);
}

具体的处理工作由handleFile完成,其中调用了openTorrent方法来打开种子文件,具体的种子文件解析见第二文章

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> protected void handleFile(AzureusCoreazureus_core,Stringfile_name, boolean open)
{
// 处理种子文件
try
{
if (open)
{
TorrentOpener.openTorrent(file_name);
// 打开种子文件

}
else
{
Filef
= new File(file_name);
if (f.isDirectory())
{
ShareUtils.shareDir(azureus_core,file_name);

}
else
{
ShareUtils.shareFile(azureus_core,file_name);
}
}
}
catch (Throwablee)
{
Debug.printStackTrace(e);
}
}

当Azureus生命周期来到各个组件都创建完毕时,会通知其监听者,从而调用 openQueuedTorrents方法来处理排队中的种子文件

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> protected void openQueuedTorrents(AzureusCoreazureus_core)
{
try
{
this_mon.enter();
core_started
= true ; // 核心启动!
}
finally
{
this_mon.exit();
}

// 处理种子队列中的种子文件
for ( int i = 0 ;i < queued_torrents.size();i ++ )
{
Object[]entry
= (Object[])queued_torrents.get(i);
Stringfile_name
= (String)entry[ 0 ]; // 种子文件名
boolean open = ((Boolean)entry[ 1 ]).booleanValue(); // 是否已经打开
handleFile(azureus_core,file_name,open);
}
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值