亞馬遜Amazon作為雲計算的領跑者推出了很多雲服務,我的同事Gopinath Taget在AutoCAD DevBlog上寫了一篇文章介紹了SQS與AutoCAD的結合應用。SQS即可以理解為一個放在雲上的消息隊列,先進先出(FIFO)。【更正,雲端的隊列與我們常規的隊列稍有不同,不能保證順序是嚴格的先進先出(FIFO),你從后面的演示例子就可以看出,出隊列的順序可能和進隊列時不一樣】保存在隊列中的消息有一定時間的存活期。通過SQS,我們可以實現位於不同地方的不同程序在不同的時間內進行通信。 比如我可以從位於北京的一個普通桌面程序發送消息到亞馬遜簡單隊列服務(SQS),發送完成后即可退出。其后位於北美的AutoCAD應用程序可以通過讀取存儲到SQS上的消息來完成北京發出的指令。
要使用Amazon SQS服務,你需要首先注冊一亞馬遜雲服務賬號,現在亞馬遜提供了為期一年的免費服務。你可以參考峻祁連的另一片文章《免費的雲技術平台--亞馬遜WEB服務AWS提供免費方式》。亞馬遜提供了幾種SDK,包括Java, Python, .net. 這里使用.net來掩飾。AWS .NET SDK可以從這里下載。安裝好AWS .NET SDK后可以通過添加到AWSSDK.dll的引用來調用AWS提供的服務。
下面我們就來模擬這個過程。首先建立一個普通的windows form應用程序作為發送端。添加到AWSSDK.dll的引用,這個dll位於C:\Program Files (x86)\AWS SDK for .NET\bin目錄下。
首先需要創建一個對象來連接到Amazon SQS。連接到SQS需要你的Access Key和Secret Key。這兩個key可以從這里找到。可以通過下面的方式把AccessKey和Secret Key以寫在代碼中。
AmazonSQS sqs = AWSClientFactory.CreateAmazonSQSClient( <Access Key placeholder>, <Secret Key placeholder>);
更好的方式是寫在配置文件App.Config中,如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="AWSAccessKey" value="*****"/> <add key="AWSSecretKey" value="*****"/> </appSettings> </configuration>
這樣在創建AmazonSQS對象時直接用如下語句即可。程序會從App.Config中查找相關的Key信息。
//Create AzazomSQS client using information of appconfig.xml
AmazonSQS sqsClient = AWSClientFactory.CreateAmazonSQSClient();
這個發送端程序要完成的工作就是向遠程的AutoCAD發送工作序列,其中有三個任務:
"Say: Hello AutoCAD" : 在AutoCAD命令行中輸出這個信息;
"Action: drawline" : 在AutoCAD中畫一條線;
"Action: drawcircle" : 在AutoCAD中畫一圓。
下面是發送端的完整代碼:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Amazon; using Amazon.SQS; using Amazon.SQS.Model; namespace SQS_Sender { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //Create AzazomSQS client using information of appconfig.xml AmazonSQS sqsClient = AWSClientFactory.CreateAmazonSQSClient(); //AmazonSQS sqs = // AWSClientFactory.CreateAmazonSQSClient( // <Access Key placeholder>, // <Secret Key placeholder> // ); try { //Create a queue if it does not exits CreateQueueRequest sqsRequest = new CreateQueueRequest(); sqsRequest.QueueName = "AutoCADJobQueue"; CreateQueueResponse sqsResponse = sqsClient.CreateQueue(sqsRequest); string myQueueUrl = string.Empty; ; if (sqsResponse.IsSetCreateQueueResult()) { myQueueUrl = sqsResponse.CreateQueueResult.QueueUrl; } //post a message to the queue SendMessage(sqsClient, myQueueUrl, "Say: Hello AutoCAD"); SendMessage(sqsClient, myQueueUrl, "Action: drawline"); SendMessage(sqsClient, myQueueUrl,"Action: drawcircle"); } catch (AmazonSQSException aEx) { MessageBox.Show(aEx.Message); } } private static void SendMessage(AmazonSQS sqsClient, string myQueueUrl, string messageBody) { SendMessageRequest sendMsgRequest = new SendMessageRequest(); sendMsgRequest.QueueUrl = myQueueUrl; sendMsgRequest.MessageBody = messageBody; sqsClient.SendMessage(sendMsgRequest); } } }
下面完成接收端。接收端一個AutoCAD插件,我們可以利用AutoCAD 2010-2012 dotNet Wizards.zip來創建一個插件模版,然后添加到AWSSDK.dll的引用。
直接貼出完整代碼如下:
using System; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System.Collections.Generic; using Amazon; using Amazon.SQS; using Amazon.SQS.Model; // This line is not mandatory, but improves loading performances [assembly: CommandClass(typeof(SQS_AutoCADReceiver.MyCommands))] namespace SQS_AutoCADReceiver { // This class is instantiated by AutoCAD for each document when // a command is called by the user the first time in the context // of a given document. In other words, non static data in this class // is implicitly per-document! public class MyCommands { [CommandMethod("DoJobFromCloud",CommandFlags.Modal)] public void DoJobFromCloud() //this method can be any name { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; //get the queue client AmazonSQS sqsClient = AWSClientFactory.CreateAmazonSQSClient( "<your access key>", "<your secret key>" ); try { string myQueueUrl = string.Empty; //checking whether the queue exits or not ListQueuesRequest lstQueueRequest = new ListQueuesRequest(); ListQueuesResponse lstQueueResponse = sqsClient.ListQueues(lstQueueRequest); if (lstQueueResponse.IsSetListQueuesResult()) { ListQueuesResult listQueueResult = lstQueueResponse.ListQueuesResult; foreach (string queueUrl in listQueueResult.QueueUrl) { ed.WriteMessage(queueUrl+ "\n"); if (queueUrl.Contains("AutoCADJobQueue")) { myQueueUrl = queueUrl; } } } if (myQueueUrl.Length > 0) //The queue exits { //Get the message number in the queue int numMessage = GetMessageNumber(sqsClient, myQueueUrl); if (numMessage > 0) { do { //receive a message ReceiveMessageRequest receiveReq = new ReceiveMessageRequest(); receiveReq.QueueUrl = myQueueUrl; ReceiveMessageResponse receiveRes = sqsClient.ReceiveMessage(receiveReq); if (receiveRes.IsSetReceiveMessageResult()) { foreach (Message msg in receiveRes.ReceiveMessageResult.Message) { if (msg.IsSetBody()) { if (msg.Body.StartsWith("Say")) { //print the message in AutoCAD ed.WriteMessage(msg.Body + "\n"); } if (msg.Body.StartsWith("Action")) { if (msg.Body == "Action: drawline") { //draw a line in AutoCAD DrawLine(); ed.WriteMessage(msg.Body + " executed!\n"); } if (msg.Body == "Action: drawcircle") { //draw a circle in AutoCAD DrawCircle(); ed.WriteMessage(msg.Body + " executed!\n"); } } } //delete the message from queue, //since we have aleady worked on it DeleteMessageRequest delMsgRequest = new DeleteMessageRequest(); delMsgRequest.QueueUrl = myQueueUrl; delMsgRequest.ReceiptHandle = msg.ReceiptHandle; sqsClient.DeleteMessage(delMsgRequest); } } numMessage = GetMessageNumber(sqsClient, myQueueUrl); } while (numMessage > 0); } } } catch (AmazonSQSException aEx) { ed.WriteMessage("\n Error: " + aEx.Message); } } private static int GetMessageNumber(AmazonSQS sqsClient, string myQueueUrl) { int numMessage = 0; GetQueueAttributesRequest req = new GetQueueAttributesRequest(); req.AttributeName.Add("All"); req.QueueUrl = myQueueUrl; GetQueueAttributesResponse res = sqsClient.GetQueueAttributes(req); if (res.IsSetGetQueueAttributesResult()) { GetQueueAttributesResult attResult = res.GetQueueAttributesResult; numMessage = attResult.ApproximateNumberOfMessages; } return numMessage; } public void DrawCircle() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (Transaction trans = db.TransactionManager.StartTransaction()) { BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable; BlockTableRecord modelSpace = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite)as BlockTableRecord; using (Circle c = new Circle()) { c.Center = new Point3d(0, 0, 0); c.Radius = 10; modelSpace.AppendEntity(c); trans.AddNewlyCreatedDBObject(c, true); } trans.Commit(); } } public void DrawLine() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (Transaction trans = db.TransactionManager.StartTransaction()) { BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable; BlockTableRecord modelSpace = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite)as BlockTableRecord; using (Line ln = new Line()) { ln.StartPoint = new Point3d(0,0,0); ln.EndPoint = new Point3d(10, 10, 0); modelSpace.AppendEntity(ln); trans.AddNewlyCreatedDBObject(ln, true); } trans.Commit(); } } } }
下面是在AutoCAD中的運行結果:
你覺得還有哪些情形可以使用Amazon簡單隊列服務(SQS)?歡迎評論大家一起討論。