首页 »编程综合 » thunderbird:基于Mozilla Thunderbird的扩展开发( 8)---进程间通信的Socket篇(续) »正文
thunderbird:基于Mozilla Thunderbird的扩展开发( 8)---进程间通信的Socket篇(续)
来源: 发布时间:星期四, 2009年1月15日 浏览:21次 评论:0
最近遇到这样 ![](/icons/92628yi.gif) 个需求:在我们 ![](/icons/92628de.gif) MFC ![](/icons/92628chengxu.gif) 中控制Thunderbird ![](/icons/92628dou2.gif) 拿到这个奇怪 ![](/icons/92628de.gif) 需求后 ![](/icons/92628dou.gif) 有了这么几个想法:1)用全局钩子试着勾住Thunderbird ![](/icons/92628dou.gif) 可细想好像不对 ![](/icons/92628dou2.gif) 2)用spy ![](/icons/92628jiajia.gif) 探查点击Thunderbird ![](/icons/92628de.gif) 各个菜单 ![](/icons/92628dou.gif) 按钮时触发 ![](/icons/92628de.gif) 事件 ![](/icons/92628dou.gif) 总归是win32平台上跑 ![](/icons/92628de.gif) ![](/icons/92628chengxu.gif) ![](/icons/92628dou.gif) 归根到底还是事件触发 ![](/icons/92628dou.gif) 从理论上说应该是可以在我们自己 ![](/icons/92628de.gif) MFC ![](/icons/92628chengxu.gif) 中模拟目标 ![](/icons/92628chengxu.gif) 中 ![](/icons/92628de.gif) 各个事件触发 ![](/icons/92628dou2.gif) 但接触到Mozilla ![](/icons/92628de.gif) ![](/icons/92628socket.gif) 方面 ![](/icons/92628de.gif) 知识后 ![](/icons/92628dou.gif) 放弃了上面 ![](/icons/92628de.gif) 想法 ![](/icons/92628dou.gif) 改用 ![](/icons/92628socket.gif) 通信来实现此需求 ![](/icons/92628dou2.gif) ![](/icons/92628yi.gif) 来Thunderbird源代码可以自行修改 ![](/icons/92628dou.gif) 因此可以加入 ![](/icons/92628yi.gif) 些代码使的成为 ![](/icons/92628yi.gif) 个类似HTTP服务器 ![](/icons/92628de.gif) 服务器端 ![](/icons/92628chengxu.gif) ![](/icons/92628dou.gif) 2来使用 ![](/icons/92628socket.gif) 进行连接和语言无关 ![](/icons/92628dou.gif) 因此C ![](/icons/92628jiajia.gif) ![](/icons/92628de.gif) ![](/icons/92628chengxu.gif) 可以和javascript ![](/icons/92628de.gif) ![](/icons/92628chengxu.gif) 完成通信 ![](/icons/92628dou.gif) 但缺点也很明显 ![](/icons/92628dou.gif) 要占用端口 ![](/icons/92628dou.gif) 只涉及到本地机器 ![](/icons/92628de.gif) 通信却使用了 ![](/icons/92628socket.gif) 这样 ![](/icons/92628de.gif) 网络通信机制 ![](/icons/92628dou2.gif) 先来介绍下完成这个功能用到 ![](/icons/92628de.gif) 基本知识:由于输入流基接口nsIInputStream没有提供任何从javascript中读取数据 ![](/icons/92628de.gif) 思路方法 ![](/icons/92628dou.gif) 而只能在C ![](/icons/92628jiajia.gif) 中读取 ![](/icons/92628dou.gif) 因此我们必须使用 ![](/icons/92628yi.gif) 个可脚本化 ![](/icons/92628de.gif) 输入流来对其进行包装 ![](/icons/92628dou.gif) 这个可脚本化 ![](/icons/92628de.gif) 输入流实现了nsIScriptableInputStream接口 ![](/icons/92628dou2.gif) 当然也可以使用其他流类型 ![](/icons/92628dou.gif) 比如为了读取 2进制数据 ![](/icons/92628dou.gif) 我们可以使用nsIBinaryInputStream ![](/icons/92628dou.gif) 反正在javascript中 ![](/icons/92628dou.gif) 你总得以其他形式 ![](/icons/92628de.gif) 流来包装基流 ![](/icons/92628dou2.gif) 在Mozilla中 ![](/icons/92628dou.gif) 网络数据 ![](/icons/92628de.gif) 读和写是在 ![](/icons/92628yi.gif) 个单独 ![](/icons/92628de.gif) 线程中进行 ![](/icons/92628de.gif) ![](/icons/92628dou.gif) 从 ![](/icons/92628socket.gif) 中读数据是异步 ![](/icons/92628de.gif) ![](/icons/92628dou.gif) 这就意味着只要 ![](/icons/92628socket.gif) 中有数据存在 ![](/icons/92628dou.gif) 就在后台读取数据 ![](/icons/92628dou.gif) 而 ![](/icons/92628chengxu.gif) 会收到数据可读 ![](/icons/92628de.gif) 通知信息 ![](/icons/92628dou.gif) 这就意味着我们需要创建 ![](/icons/92628yi.gif) 个监听者来监听这个信息 ![](/icons/92628dou2.gif) 对于异步读取数据 ![](/icons/92628dou.gif) 我们还需要创建 ![](/icons/92628yi.gif) 个输入流Pump,的所以Mozilla选择“泵”这个名称是 ![](/icons/92628yinwei.gif) 当有数据存在时它就发送小块 ![](/icons/92628de.gif) 数据给监听者 ![](/icons/92628dou2.gif) 这个Pump实现了nsIInputStreamPump接口 ![](/icons/92628dou.gif) 这个接口继承自nsIRequest,后者提供了暂停连接和特定 ![](/icons/92628de.gif) 缓存Cache行为(这些 ![](/icons/92628yi.gif) 般 ![](/icons/92628de.gif) ![](/icons/92628socket.gif) ![](/icons/92628chengxu.gif) 用不上 ![](/icons/92628dou.gif) 但像HTTP这样构建在 ![](/icons/92628socket.gif) 上 ![](/icons/92628de.gif) 高层次应用会用得上 ![](/icons/92628de.gif) ) ![](/icons/92628dou2.gif)
pump.asyncRead(dataListener,null); asyncRead ![](/icons/92628hanshu.gif) 用来给Pump对象设置 ![](/icons/92628yi.gif) 个监听者 ![](/icons/92628dou.gif) 当有数据到来或连接关闭时 ![](/icons/92628dou.gif) 监听者就会被 ![](/icons/92628diaoyong.gif) ![](/icons/92628dou2.gif) 监听者对象应该实现nsIStreamListener接口 ![](/icons/92628dou.gif) 这个接口有 ![](/icons/92628yi.gif) 个思路方法onDataAvailable,当有额外数据可读时就会被 ![](/icons/92628diaoyong.gif) ![](/icons/92628dou2.gif) 此接口继承自nsIRequestObserver ![](/icons/92628dou.gif) 这个接口有两个思路方法 ![](/icons/92628dou.gif) onStartRequest ![](/icons/92628dou.gif) onStopRequest ![](/icons/92628dou.gif) 这两个思路方法在输入流 ![](/icons/92628de.gif) 开始和结束时分别被 ![](/icons/92628diaoyong.gif) ![](/icons/92628dou.gif) 因此这3个思路方法都应该实现 ![](/icons/92628dou2.gif) 下面是客户端代码 ![](/icons/92628dou.gif) 使用最简单 ![](/icons/92628de.gif) 阻塞式TCP连接: void CClientTestDlg::OnSend![](/icons/92628kh.gif) {//发送按钮 UpdateData ; (str.IsEmpty ) { list.InsertString(0,"发送![](/icons/92628de.gif) 串不能为空 "); ; } //strcpy(msg.msg,(LPCTSTR)str); char szText[1024]; strcpy(szText,(LPCTSTR)str); SOCKET = :: (AF_INET,SOCK_STREAM,IPPROTO_TCP); (![](/icons/92628socket.gif) INVALID_SOCKET) { list.InsertString(0,"创建 发生![](/icons/92628cuowu.gif) "); ; } SOCKADDR_IN servAddr; servAddr.sin_family = AF_INET; servAddr.sin_port = htons(25501); servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); (::connect( ,(sockaddr*)&servAddr, (servAddr)) -1) { list.InsertString(0,"连接服务器发生![](/icons/92628cuowu.gif) "); ; } (::send( ,szText,strlen(szText),0) SOCKET_ERROR)// recv(ServerSocket,buf, (buf),0); { list.InsertString(0,"发送数据发生![](/icons/92628cuowu.gif) "); ; } sRecv = SOCKET_ERROR; char buffer[1024]; mem (buffer,0,1024); sRecv = recv( , buffer, 1024, 0 ); DWORD dwerr = WSAGetLastError ; CString str; str.Format("%s",buffer); list.InsertString(0,str); ::close ( ); }
服务器端代码 ![](/icons/92628dou.gif) 通过修改Thunderbird源代码 ![](/icons/92628dou.gif) 使的成为 ![](/icons/92628yi.gif) 个类似HTTP服务器 ![](/icons/92628de.gif) 服务器端 //*************************************************************************** //Author: phinecos //Date : 2008/5/19 //Description:服务器监听对象 //Contact:[email protected] //*************************************************************************** //服务器端对象 const CI = Components. erfaces, CC = Components. es, CR = Components.results; var gServer = null;//服务器对象 var gUtility = null;//工具类对象 //var gConnection = null;//客户端连接对象 function tBirdB fServerOnLoad![](/icons/92628kh.gif) {//启动监听服务器 try { gUtility = tBirdB fUtility ;//新建日志对象 gUtility.initialize ; gUtility.log("tBirdB fServerUi.tBirdB fServerOnLoad", "Thunderbird b f server loaded"); gServer = tBirdB fServer ;//新建服务器对象 gServer.initialize ;// 化服务器端 gUtility.log("tBirdB fServerOnLoad","start server"); } catch(err) { gUtility.log("tBirdB fServerOnLoad","start server failed"); } } function tBirdB fServerOnClose![](/icons/92628kh.gif) {//关闭服务器 gUtility.log("tBirdB fServerOnClose","close server"); gServer.finalize ; gServer = null; gUtility = null; } function tBirdB fServer![](/icons/92628kh.gif) { this.serverSocket = null;//服务器端![](/icons/92628socket.gif) this.port = null;//服务器端口 this.initialized = false; gUtility.log("tBirdB fServer constructor","construct ok"); } tBirdB fServer.prototype = { getServerSocket: function![](/icons/92628kh.gif) {//创建服务器端![](/icons/92628socket.gif) this.serverSocket = CC["@mozilla.org/network/server- ;1"].createInstance(CI.nsIServerSocket); (!this.serverSocket) { gUtility.log("tBirdB fServer.getServerSocket","Unable to get a server "); } ![](/icons/92628else.gif) { try { this.serverSocket.init(this.port, false, -1);// 化 ,绑定到端口port上 this.serverSocket.asyncListen(tBirdB fServerSocketListener);//开始异步监听 gUtility.log("tBirdB fServer.getServerSocket","Server established"); } catch(e) { gUtility.log("tBirdB fServer.getServerSocket, Server established error"); this.serverSocket = null; } } }, closeServerSocket: function![](/icons/92628kh.gif) {//关闭服务器端![](/icons/92628socket.gif) (!this.serverSocket) { this.serverSocket.close(null); this.serverSocket = null; } }, initialize: function![](/icons/92628kh.gif) { (this.initialized) { ; } this.port = 25501;//获取端口号 gUtility.log("tBirdB fServer.initialize","port is: "+this.port); this.getServerSocket ;//创建服务器端![](/icons/92628socket.gif) this.initialized = true; gUtility.log("tBirdB fServer.initialize","initialize ok!"); }, finalize: function![](/icons/92628kh.gif) {//退出![](/icons/92628chengxu.gif) (!this.initialized) { ; } this.closeServerSocket ;//关闭服务器端![](/icons/92628socket.gif) gUtility.log("tBirdB fServer.finalize","server Finalized"); }, } var listener = { finished : function(data) {//数据读取完毕 ParseCommand(data);//解析命令字 } } const tBirdB fServerSocketListener = { onSocketAccepted: function(serverSocket, clientSocket) {//接受来自客户端![](/icons/92628de.gif) 请求 gUtility.log("tBirdB fServerSocketListener.onSocketAccepted","Got a connection from: " + clientSocket.host + ":" + clientSocket.port); var outputData = "Ok,server get your command"; var outstream = clientSocket.openOutputStream(0,0,0); outstream.write(outputData,outputData.length); try { //打开输入流 var stream = clientSocket.openInputStream(0,0,0); var instream = Components. es["@mozilla.org/scriptableinputstream;1"].createInstance(Components. erfaces.nsIScriptableInputStream); instream.init(stream); var dataListener = { data : "",//来自客户端 数据 onStartRequest: function(request, context){}, onStopRequest: function(request, context, status){ instream.close ; outstream.close ; listener.finished(this.data); }, onDataAvailable: function(request, context, inputStream, off , count){ this.data instream.read(count); }, }; var pump = Components. es["@mozilla.org/network/input-stream-pump;1"].createInstance(Components. erfaces.nsIInputStreamPump); pump.init(stream, -1, -1, 0, 0, false); pump.asyncRead(dataListener,null); } catch(err) { gUtility.log("tBirdB fServerConnection. Socket",e); false; } }, onStopListening: function(serverSocket, status) {//服务器端停止监听 gUtility.log("tBirdB fServerSocketListener.onStopListening","Server has stopped listening"); } }
相关文章
读者评论
发表评论
|
|