`
dato0123
  • 浏览: 913695 次
文章分类
社区版块
存档分类
最新评论

基于Mozilla Thunderbird的扩展开发(五)---进程间通信之Socket篇(上)

 
阅读更多

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype>

20080506.bmp

Mozilla扩展系列链接:

1浅谈基于Mozilla Thunderbird的扩展开发

2基于Mozilla平台的扩展开发(续)----XPCOM组件篇

3基于Mozilla Thunderbird的扩展开发(三)---如何获取邮件的完整信息

4基于Mozilla Thunderbird的扩展开发(四)---修改源代码实现自动保存附件

5基于Mozilla Thunderbird的扩展开发(五)---进程间通信之Socket篇(上)

这个系列的前两篇文章主要是根据自己的需求,对Thunderbird的源代码进行修改,改进了Thunderbird的现有功能,关注点都在Thunderbird的老本行---邮件客户端的实现上,那是否Thunderbird就仅仅是一个邮件客户端呢?在我看来,并非如此,它源自Mozilla内核,就继承了Mozilla平台的光荣传统,应该视为一个优秀的可扩展的开发平台,更进一步来看,Mozilla的文化深入其骨髓,可以看到后来AdobeFlex,MicroSoftWPF都吸收了Mozilla平台界面与逻辑相分离的思想,所以接下来几篇文章我想写一个比较有意思的方面----进程间通信。

进程间通信的概念在操作系统中有过详细的介绍,方法很多,我主要关注其中两种:socket通信,Pipe(管道)通信。

本文的目的就是开发一个扩展,展示TCP/IP socket技术在Mozilla扩展开发中的应用。

服务器端主代码:

consttBirdBiffServerUi=
{
tBirdBiffServerOnLoad:
function()
{//启动服务器
//removetoavoidduplicateinitialization
removeEventListener("load",tBirdBiffServerUi.tBirdBiffServerOnLoad,true);
tBirdBiffCommon.setIconPosition();
//设置图标位置
//创建服务器对象并初始化
varserver=Components.classes["@phinecos.cnblogs.com/TBbiff/server;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
server.initialize();
server.addWindow(window);
//保存当前窗口
server=null;
}
,
tBirdBiffServerOnClose:
function()
{//关闭服务器
//removetoavoidduplicateinitialization
removeEventListener("close",tBirdBiffServerUi.tBirdBiffServerOnClose,true);

//移除当前窗口
varserver=Components.classes["@dpwhite.com/thunderbirdbiff/server;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
server.removeWindow(window);
server
=null;
}

}


addEventListener(
"load",tBirdBiffServerUi.tBirdBiffServerOnLoad,true);
addEventListener(
"close",tBirdBiffServerUi.tBirdBiffServerOnClose,true);


服务器类,负责创建服务器端socket,并异步监听来自客户端的请求,管理邮箱状态的变化和来自客户端的连接。

服务器类
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->constCI=Components.interfaces,CC=Components.classes,CR=Components.results;
constnewMail
="1";
constnoMail
="0";
constserverError
="9";

tBirdBiffServer.classID
=Components.ID("{d2c9b4c6-2851-4d25-8cb6-3d3b037f8e1e}");//组件ID
tBirdBiffServer.contractID="@phinecos.cnblogs.com/TBbiff/server;1";
tBirdBiffServer.classDescription
="TBbiffServerService";

functiontBirdBiffServer()
{
this.utility=CC[utilityContractID].getService(CI.nsISupports).wrappedJSObject;//工具类对象
this.prefs=CC["@mozilla.org/preferences-service;1"].getService(CI.nsIPrefBranch);
this.connections=CC["@mozilla.org/supports-array;1"].createInstance(CI.nsICollection);//客户端连接集合
this.useAnimation=null;//是否使用动画效果
this.mailStatus=noMail;//邮箱状态
this.serverSocket=null;//服务器端socket
this.port=null;//服务器端口
this.windowCollection=CC["@mozilla.org/supports-array;1"].createInstance(CI.nsICollection);//保存的窗口集合
this.initialized=false;//是否已经初始化
}


broadcast:
function()
{//向客户端发送数据
vardeadConnections=newArray();//已断开的连接
varstatus=this.mailStatus;//获取当前邮箱状态
varcount=this.connections.Count();//来自客户端的连接数目

//依次向各个客户端发送服务器的邮箱状态
for(vari=0;i<count;i++)
{
varconnection=this.connections.GetElementAt(i);//来自客户端的连接
connection=connection.wrappedJSObject;

//发送数据给客户端
if(!connection.broadcast(status))
{
connection.closeSocket();
//关闭此断开的连接
deadConnections[i]=connection;
}

else
{
deadConnections[i]
=null;
}


connection
=null;
}


for(vari=0;i<deadConnections.length;i++)
{//移除已经断开的连接
if(deadConnections[i]!=null)
{
this.removeConnection(deadConnections[i]);
}

}


deadConnections
=null;
count
=null;
}
,

addConnection:
function(value)
{//加入新的来自客户端的连接
this.connections.AppendElement(value);
}
,

removeConnection:
function(value)
{//移除连接
this.connections.RemoveElement(value);
}
,
getServerSocket:
function()
{//创建服务器端socket,并开始异步监听来自客户端的request
this.serverSocket=CC["@mozilla.org/network/server-socket;1"].createInstance(CI.nsIServerSocket);
if(!this.serverSocket)
{
alert(
"Unabletogetaserversocket");
}

else
{
try
{
this.serverSocket.init(this.port,false,-1);//初始化服务器端socket,绑定到端口号port
this.serverSocket.asyncListen(tBirdBiffServerSocketListener);//开始异步监听来自客户端的请求
}

catch(e)
{
this.serverSocket=null;
}

}

}
,
closeServerSocket:
function()
{//关闭服务器端socket
if(!this.serverSocket)
{
this.serverSocket.close(null);
this.serverSocket=null;
}

}
,
initialize:
function()
{//初始化服务器
if(this.initialized)
{//已经初始化过了
return;
}

this.port=25501;//设置服务器监听端口
this.useAnimation=true;
this.getServerSocket();//创建服务器端socket并开始监听
this.monitorBiff(true);//监控状态变化
this.initialized=true;
}
,
monitorBiff:
function(isStarting)
{//监控邮箱状态变化
varsessionService=CC["@mozilla.org/messenger/services/session;1"].getService(CI.nsIMsgMailSession);
if(isStarting)
{
sessionService.AddFolderListener(tBirdBiffServerBiffStateListener,CI.nsIFolderListener.intPropertyChanged);
//增加监听者
}

else
{
sessionService.RemoveFolderListener(tBirdBiffServerBiffStateListener,CI.nsIFolderListener.intPropertyChanged);
//移除监听者
}


sessionService
=null;
}
,

closeAllConnections:
function()
{//关闭所有来自客户端的连接
varcount=this.connections.Count();
for(vari=0;i<count;i++)
{
varconnection=this.connections.GetElementAt(i);
connection
=connection.wrappedJSObject;
connection.closeSocket();
connection
=null;
}


count
=null;
this.connections.Clear();
}
,
finalize:
function()
{//析构函数
if(!this.initialized)
{
return;
}


this.closeServerSocket();//关闭服务器端socket
this.monitorBiff(false);//移除监听邮箱状态的监听者
this.closeAllConnections();//关闭所有来自客户端的连接
}
,

updateUi:
function(window)
{//刷新界面状态
varstate;
vartip="T-BirdBiff:";
varstatus=window.document.getElementById("thunderbird-biff");

switch(this.mailStatus)
{
casenoMail:
{//没有新邮件
tip+=this.getLocalizedString("noNewMail");
state
="noMail";
break;
}


casenewMail:
{//有新邮件
tip+=this.getLocalizedString("newMail");
if(this.useAnimation)
{
state
="newMailAni";//usinggifhereduetoanimation
}

else
{
state
="newMail";
}


break;
}


default:
{//error
this.utility.logError("Unexpectedresult:"+this.mailStatus);
tip
=this.getLocalizedString("weirdness");
state
="weirdness";
break;
}

}


status.setAttribute(
"tooltiptext",tip);
status.setAttribute(
"biffState",state);
tip
=null;
state
=null;
status
=null;
}
,

setMailStatus:
function(value)
{//设置邮箱状态
if(this.MailStatus==value)
{//没有变化
return;
}

this.mailStatus=value;
//邮箱状态发生改变,逐个窗口通知其更新状态,这些窗口都是服务器端的Observer
varserver=CC[tBirdBiffServer.contractID].getService(CI.nsISupports).wrappedJSObject;
varwindowCollection=server.getWindowCollection();
varcount=windowCollection.Count();
for(vari=0;i<count;i++)
{
varwindow=windowCollection.GetElementAt(i);
this.updateUi(window);//更新此窗口状态
window=null;
}


this.broadcast();//将服务器的邮箱状态通知给各个客户端

windowCollection
=null;
count
=null;
server
=null;
}
,

check:
function()
{//检查服务器邮箱状态
tBirdBiffServerBiffStateListener.clearIntervalTimeout();//清除此前的定时器
this.setMailStatus(this.checkServers());//实际的检查动作
}
,

checkServers:
function()
{
try
{
constbiffShowsMailReady
=0;
//帐户管理器
varaccountManager=CC["@mozilla.org/messenger/account-manager;1"].getService(CI.nsIMsgAccountManager);
if(accountManager)
{
//获取此用户的所有服务器
varservers=accountManager.allServers;
varnumServers=servers.Count();

for(vari=0;i<numServers;i++)
{
varserver=servers.GetElementAt(i).QueryInterface(CI.nsIMsgIncomingServer);

if(server.rootFolder!=server.rootMsgFolder)
{
continue;
}


if(server.type!="pop3"&&server.type!="imap")
{
if(server==accountManager.localFoldersServer)
{
alert(
"tBirdBiffServer.checkServers"+server.prettyName+"appearstobeLocalFolders");
}

else
{
alert(
"Non-pop3,IMAP,orLocalFoldersserverfound.Typeis"+server.type+",nameis"+server.prettyName);
continue;
}

}

if(server.biffState==biffShowsMailReady)
{//有新邮件到来
server=null;
servers
=null;
numServers
=null;
accountManager
=null;
returnnewMail;
}

}

//没有新邮件
servers=null;
numServers
=null;
accountManager
=null;
returnnoMail;
}

else
{
accountManager
=null;
this.utility.logError("Unabletogetaccountmanager");
returnserverError;
}

}

catch(e)
{
accountManager
=null;
returnserverError;
}

}
,

来自客户端的连接对象类:
functiontBirdBiffServerConnection()
{
this.wrappedJSObject=this;
}


tBirdBiffServerConnection.prototype
=
{
socket:
null,//客户端对应的socket
outputStream:null,//输出流

setSocket:
function(value)
{//保存来自客户端的socket连接
try
{
this.outputStream=value.openOutputStream(CI.nsITransport.OPEN_BLOCKING|CI.nsITransport.OPEN_UNBUFFERED,0,0);//打开输出流,类型为阻塞型,无缓冲区
}

catch(e)
{
returnfalse;
}

if(!this.outputStream)
{
returnfalse;
}

this.socket=value;
returntrue;
}
,

closeSocket:
function()
{//关闭来自客户端的socket
if(this.outputStream)
{//关闭输出流
this.outputStream.close(null);
this.outputStream=null;
}

if(this.socket)
{//关闭对应的socket
this.socket.close(null);
this.socket=null;
}

}
,

broadcast:
function(value)
{//向客户端发送数据
if(!this.outputStream)
{
this.closeSocket();
returnfalse;
}

try
{
this.outputStream.write(value,value.length);//发送数据
}

catch(e)
{
this.closeSocket();
returnfalse;
}

returntrue;
}

}


服务器监听类,负责监听来自客户端的各个请求:

functiontBirdBiffServerConnection()
{
this.wrappedJSObject=this;
}


tBirdBiffServerConnection.prototype
=
{
socket:
null,//客户端对应的socket
outputStream:null,//输出流

setSocket:
function(value)
{//保存来自客户端的socket连接
try
{
this.outputStream=value.openOutputStream(CI.nsITransport.OPEN_BLOCKING|CI.nsITransport.OPEN_UNBUFFERED,0,0);//打开输出流,类型为阻塞型,无缓冲区
}

catch(e)
{
returnfalse;
}

if(!this.outputStream)
{
returnfalse;
}

this.socket=value;
returntrue;
}
,

closeSocket:
function()
{//关闭来自客户端的socket
if(this.outputStream)
{//关闭输出流
this.outputStream.close(null);
this.outputStream=null;
}

if(this.socket)
{//关闭对应的socket
this.socket.close(null);
this.socket=null;
}

}
,

broadcast:
function(value)
{//向客户端发送数据
if(!this.outputStream)
{
this.closeSocket();
returnfalse;
}

try
{
this.outputStream.write(value,value.length);//发送数据
}

catch(e)
{
this.closeSocket();
returnfalse;
}

returntrue;
}

}


consttBirdBiffServerSocketListener
=
{
onSocketAccepted:
function(serverSocket,clientSocket)
{//接受来自客户端的请求
varconnection=newtBirdBiffServerConnection();//新建一个连接对象
//保存当前接收的连接
if(connection.setSocket(clientSocket))
{
varserver=CC[tBirdBiffServer.contractID].getService(CI.nsISupports).wrappedJSObject;
//向客户端发送数据
if(connection.broadcast(server.getMailStatus()))
{
server.addConnection(connection);
//保存连接对象到在线连接集合中
}

else
{
alert(
"connectionNOTadded");
}

server
=null;
}

else
{
alert(
"Creatingconnectionfailed");
}

connection
=null;
}
,

onStopListening:
function(serverSocket,status)
{//服务器停止监听
alert("Serversockethasstoppedlistening");
}

}


服务器邮箱状态监听者,负责监视邮箱的状态变化:

consttBirdBiffServerBiffStateListener=
{
timer:
null,//定时器,负责定时检查邮箱状态
clearIntervalTimeout:function()
{//清除定时器
if(this.timer)
{
this.timer=CC["@mozilla.org/timer;1"].getService(CI.nsITimer);
this.timer.cancel();
this.timer=null;
}

else
{
alert(
"Timerisnull");
}

}
,

OnItemIntPropertyChanged:
function(item,property,oldValue,newValue)
{//参见Thunderbird源代码,此函数负责监视各个文件夹的属性变化,当有新邮件到来时,property的值为“BiffState”
if(property.toString()!="BiffState")
{
return;
}

this.clearIntervalTimeout();
//启动一个定时器
this.timer=CC["@mozilla.org/timer;1"].getService(CI.nsITimer);
this.timer.initWithCallback(tBirdBiffServerCheckCallback,1000,this.timer.TYPE_ONE_SHOT);
}

}

实际的检查邮箱状态的处理过程放在tBirdBiffServerCheckCallback函数中。

consttBirdBiffServerCheckCallback=
{//定时检查邮箱状态的处理函数
notify:function(timer)
{
varserver=CC[tBirdBiffServer.contractID].getService(CI.nsISupports).wrappedJSObject;
server.check();
//检查邮箱状态
server=null;
}

}


Ok,本文用
javascript,遵循XPCOM规范实现了一个简单的TCP服务器,服务器类型为阻塞式I/O,客户端代码将在下一篇文章中介绍。

Reference:

1 https://addons.mozilla.org/en-US/thunderbird/addon/3788

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics