ارسالی مروه
وب سرویسها سیستمی بسیار ساده دارند و از آنها میتوان به عنوان ابزاری جهت برقراری ارتباط بین سیستمهای با Platformهای مختلف استفاده کرد، ولی با تمام قابلیتها و امکاناتی که وبسرویسها دارند این تکنولوژی در برخی موارد به اندازه کافی انعطافپذیر و سریع نیست و لذا پاسخگوی گروه خاصی از نیازها نیست.
همانگونه که میدانید وبسرویسها امکانی جهت دسترسی به اشیاء و توابع از طریق شبکه را فراهم میکنند وب سرویسها سیستمی بسیار ساده دارند و از آنها میتوان به عنوان ابزاری جهت برقراری ارتباط بین سیستمهای با Platformهای مختلف استفاده کرد، ولی با تمام قابلیتها و امکاناتی که وبسرویسها دارند این تکنولوژی در برخی موارد به اندازه کافی انعطافپذیر و سریع نیست و لذا پاسخگوی گروه خاصی از نیازها نیست. بزرگترین عاملی که این محدودیت را ایجاد میکند نیاز وب سرویسها به IIS و یا به عبارت دیگر ASP.NET runtime میباشد. جهت فائقآمدن به این مسایل میتوان از Dot NET Remoting استفاده کرد. در واقع Dot NET Remoting هم دقیقاً همان سرویسی را فراهم میکند که وب سرویسها فراهم میکنند ولی دارای ویژگیهای خاصی میباشد که انعطاف و سرعت زیادی نسبت به وب سرویسهای عادی فراهم میکند.
●مقدمه
بهطور کلی اگر ساختار یک وب سرویس، (منظور از وب سرویس در اینجا NET ASP . وبسرویس میباشد) را بررسی کنیم همواره دو جزء در ساختار آن وجود دارد: جزء اول همان کلاسهایی میباشد که درست میکنید. به عبارت دیگر در داخل این کلاسها منطقکاری وبسرویس و توابع عمومی و خصوصی وب سرویس قرار میگیرند و پس از کامپایل، این کلاسها به یک dll تبدیل میشوند. جزء بعدی یک وب سرویس که همواره موردنیاز میباشد برنامهای است که به یک پورت سیستم گوش میدهد و درخواستهای کلاینتها را میگیرد و به جزء اول میدهد و پس از پردازش پاسخ را گرفته و به کلاینت ارسال میکند. در تولید وبسرویسهای عادی تقریباً تمام تمرکز روی جزء اول یعنی کلاسهای آن است. جزء بعدی همان IIS است که کافی است در برخی موارد تنظیمات خاصی روی آن انجام دهیم. با استفاده از NET Remoting. سیستمهایی جهت دسترسی از طریق شبکه فراهم خواهیم کرد که در واقع دو بخش یک وب سرویس در آنها هم وجود دارد، ولی اینبار میتوانیم ازIIS استفاده نکنیم و خودمان برنامه میزبان (منظور برنامهای که به شبکه گوش میدهد و تبادل اطلاعاتی بین کلاینتها و کلاسهای ما را فراهم میکند) را بنویسیم. با این توصیف در واقع میتوان گفت که ASP.NET Web Serviceها نوع سادهشدهای از سیستمهایی هستند که توسط NET Remoting. میتوان تولید کرد چرا که در استفاده از ASP.NETWeb Serviceها مجبور به استفاده از IIS به عنوان برنامه میزبان هستیم. قبل از اینکه شروع به پیادهسازی یک نمونه کامل نماییم، با یک دید کلی اجزاء سیستم پیادهسازی شده توسط NET Remoting را مورد بررسی قرار میدهیم.
●کلاسها
در سمت سرور، remote object همان کلاسهایی میباشند که منطق اصلی کاری را تشکیل میدهند. این کلاسها به صورت یک dll روی سرور قرار میگیرند و توابع public این کلاسها هستند که در نهایت از طریق کلاینتها فراخوانی شده و مورد استفاده قرار میگیرند. Formatter کلاسی است که پاسخهای سرور (مقادیر ارسالی از remote object) را که به صورت یک سری اشیاء میباشند را گرفته و با کدبندی خاصی به یک سری از بایتها تبدیل میکند که مناسب جهت ارسال از طریق شبکه میباشد. همچنین درخواستهایی را هم که کلاینت ارسال میکند از کدبندی خاص آن خارج کرده و تبدیل به یک شیء میکند که قابلفهم برای remote object میباشد. سمت کلاینت نیزformatter دقیقاً همین کار را انجام میدهد ولی جهت عکس. به عملیات تبدیل یک شیء به فرمتی قابلارسال و یا نگهداری که توسط Formatter انجام میشود Serialize و به عکس این عمل Deserialize میگویند. Channel های سمت کلاینت و سرور پروتکل ارتباطی بین کلاینت و سرور و تنظیمات مربوط به آن را تعیین میکنند. اینها در واقع همان برنامه میزبان هستند که در سمت سرور در حالت Listening قرار دارد و در سمت کلاینت به صورت کلاینت میباشند. اما کلاس Proxy که فقط در سمت کلاینت وجود دارد کلاسی است که دقیقاً مانند کلاسهای داخل remote object میباشد. کلاینت قادر به فراخوانی توابع remote object به صورت مستقیم و بیواسطه نیست چرا که remote object روی سیستم دیگری در شبکه قرار دارد و لذا کلاسی تحت عنوان کلی Proxy با همان توابع Public که remote object فراهم میکند در سمت کلاینت ایجاد میشود که از دید کلاینت همانند سایر کلاسهای عادی میباشد؛ ولی وقتی کلاینت تابعی از این کلاس را فراخوانی میکند این تابع یک پیام جهت فراخوانی تابع مشابه خود درremote object ایجاد کرده و ارسال میکند و پس از دریافت پاسخ، نتیجه را در اختیار کلاینت قرار میدهد. توجه داشته باشید که تمام این کلاسها به طور کامل در اختیار شما میباشند و شما میتوانید هر تغییر منطقی موردنیاز را در هر کدام از این کلاسها اعمال کنید و این همان انعطافپذیری کاملی میباشد که NET Remoting . در اختیار شما قرار میدهد. البته تولید تمام این کلاسها احتمالاً برای برخی زیاد هم خوشایند نخواهد بود. چرا که قطعاً زمان زیادی صرف تولید و اشکالزدایی آنها میشود. جهت رفع این مشکل میتوانید از NET. کمک بگیرید چرا که اگر نیازی به قابلیتهای خاص در این سا ختار ندارید. داتنت تمام این کلاسها را با رفتار عادی آنها برای شما تولید میکند؛ مگر دو کلاس که میبایستی شما آنها را تولید کنید. همانطور که حدس زدید یکی کلاس remote object میباشد که رفتار اصلی سیستم شما و قابلیتهایی که میخواهید ارایه دهید در این کلاس قرار دارد و دیگری برنامه یا کلاس میزبان میباشد که قسمت channel را فراهم میکند. در بیشتر موارد هدف استفاده از NET Remoting . بینیاز شدن از IIS یا ASP.NET Runtime میباشد. در ادامه مثال کاملی که در آن به جای IIS از یک برنامه console استفاده میشود را بررسی میکنیم. بهعبارت دیگر برنامه میزبان یک console Application میباشد. در مثال ارایه شده برنامه کلاینت و سرور به صورت console میباشند تا ضمن حفظ سادگی، رفتار دقیق کلاینت و سرور قابل مشاهده باشد. بدیهی است در صورت تمایل میتوانید با انجام چند تغییر جزیی آنها را به برنامههای windows form تبدیل کنید. در ادامه راهنماییهایی هم جهت این تبدیل آورده شده است. (کدهای آماده مثال را میتوانید از سایت ماهنامه شبکه دانلود کنید).
●یک مثال
به مثال زیر توجه کنید. همانطور که اشاره شد Remote Object کلاس یا کلاسهایی است که منطق اصلی موردنظر سیستم در آن قرار دارد. در اینجا یک کتابخانه ساده (dll) یا یک تابع عمومی را به عنوان remote object پیادهسازی میکنیم. همانطور که ملاحظه میکنید از توابع console استفاده شده تا پیامهای مناسبی هنگام فراخوانی سازنده کلاس و یا تابع Hello در خروجی command Prompt چاپ شود. برای تولید این remote object میتوانید یک پروژه از نوع classlibrary درNET. ایجاد کرده و کد مربوط را در کلاسی که به صورت پیشفرضNET . در پروژه ایجاد میکند بنویسید و یا میتوانید کد را در یک فایل متنی ساده تایپ کنید و با پسوند.cs ذخیره کنید و با استفاده از دستور زیر آن را کامپایل کنید: .Csc/t:library/out:My Remote object
dll My Remote object.cs
توجه داشته باشید که remote object از این کلاس ارثبری کند (کلاس Marshal By Refobject قابلیتهای خاصی به کلاسی که از او ارثبری کند میدهد تا آن کلاس جهت ارایه سرویسهای ماندگار در حافظه (lifetime) بهینه شود).
using System;
using System.Runtime.Remoting;
namespace Client
{
class Client
{
static void Main(string[] args)
{
RemotingConfiguration.Configure(“Client.exe.config”);
MyRemoteObject.MyRemoteObject obj=new MyRemoteObject.MyRemoteObject();
Console.WriteLine(obj.Hello());
Console.ReadLine();
}
}
}
Remote Server
قسمت بعدی پیادهسازی remote server و به عبارت دیگر، برنامه میزبان میباشد، برنامه میزبان و remote object را میتوانید در یک فایل یا اسمبلی پیادهسازی کنید، ولی استفاده از دو فایل متفاوت قابلیت استفاده مجدد (reuse ability) سیستم را بالا میبرد. وظیفه برنامه میزبان، درست کردن یک کانال ارتباطی و گوش دادن به یک پورت سیستم میباشد تا به این وسیله درخواستهای کلاینتها را گرفته و به remote object بدهد. کانال ارتباطی remote server یا برنامه میزبان را میتوان با استفاده از فایل پیکربندی و یا با استفاده از برنامهنویسی تنظیم نمود که هر کدام معایب و مزایای خاصی دارد. وقتی که از فایل پیکربندی (configuration file) استفاده میشود، کدنویسی لازم در برنامه میزبان به حداقل میرسد و همچنین جهت تعویض تنظیمات کانال (به عنوان مثال شماره پورت، یا پروتکل و یا …) نیازی به دستکاری کدبرنامه و کامپایل مجدد آن ندارید، بلکه فقط کافیاست تنظیمات موردنظر را در فایل پیکربندی انجام دهید. فایل پیکربندی فایلی است با فرمت XML که اطلاعات کانال را در آن قرار میدهند. برنامه میزبان هنگام اجرا، اطلاعات فایل پیکربندی را خوانده و با توجه به تنظیماتی که در آن ثبت شده، کانال ارتباطی را ایجاد میکند، البته در صورتی که از فایل پیکربندی استفاده نکنید نیز مزیت خاصی خواهید داشت و آن تغییر دادن تنظیمات کانال در زمان اجرا توسط برنامه میباشد. در اینجا جهت تولید برنامه میزبان از فایل پیکربندی استفاده خواهیم کرد. اسم فایل پیکربندی را همنام با فایل اجرایی برنامه میزبان بگذارید با پسوند config. در این صورت نام فایل Simpleserver.config خواهد شد. کدهای داخل این فایل به صورت زیر میباشند.
<configuration>
<system.runtime.remoting>
<application name=”Client”>
<client url=”tcp://localhost:۹۰۰۰/Server”>
<wellknown
type=”MyRemoteObject.MyRemoteObject, MyRemoteObject”
url=”tcp://localhost:۹۰۰۰/MyRemoteObject”/>
</client>
<channels>
<channel ref=”tcp client” />
</channels>
</application>
</system.runtime.remoting>
</configuration>
همانطور که ملاحظه میکنید اطلاعات کانال و remote object در داخل عنصرsystem.runtime.remoting قرار دارد. عنصر application در فیلد name ، نام سرور را مشخص میکند و در داخل عنصر service مشخصات remote object قرار دارد دو فیلد wellknown و mode مربوط به دستهبندی remote objectها میباشد که در ادامه دستهبندی و انواع مختلف remote objectها را توضیح خواهم داد. فعلاً این دو فیلد را همینگونه بپذیرید. در فیلد type مشخص میشود که این سرویس مربوط به کدام remote object میباشد. در این فیلد به زیرساخت NET Remoting. گفته میشود که در کدام اسمبلی و در چه کلاس و namespaceای در آن اسمبلی remote object قرار دارد. اگر به فایل توجه کنید، مقدار رشتهای فیلد type با کاما (,) دو قسمت شده است قسمت اول namespace و کلاس مربوط به remote object را مشخص میکند و قسمت دوم نام اسمبلی مربوط به remote object را. (درNET. کدهای نوشته شده در بستههای خاصی به نام assembly بستهبندی میشوند. هر اسمبلی دستوراتی به زبان IL و یک سری metadata دارد که NET runtime. با استفاده از این اطلاعات آن را اجرا میکند. توجه داشته باشید که یک اسمبلی میتواند در چند فایل باشد و یا برعکس چند اسمبلی در یک فایل. در اینجا اسمبلی remote object ما در در داخل یک فایل همنام با اسمبلی آن قرار دارد.) در فیلد Object Url آدرسی را مشخص میکنیم که قرار است کلاینتها جهت دسترسی به remote object این آدرس را بدهند. بعداً در فایل پیکربندی برنامه کلاینت خواهید دید که فیلدی با نام Url وجود دارد که آدرس remote object را در آن خواهیم نوشت. در این آدرس پس از مشخص کردن پروتکل و IP آدرس کامپیوتری که برنامه میزبان در آن قرار دارد، مقداری که به فیلد Object Url دادهایم را در آن قرار خواهیم داد. فیلد Object Url میتواند یک URL کامل باشد بدین صورت که remote object در روی سیستم دیگری در وب قرار دارد و یا حتی remote object خود یک وب سرویس میباشد. در اینجا به این فیلد فقط نام اسمبلی remote object را میدهیم و کلاینت هم در فایل پیکربندی خود در فیلد Url از همین نام استفاده خواهد کرد. اگر دقت کرده باشید، متوجه شدهاید که مشخصات remote object در داخل عنصر قرار گرفته است. در واقع جالب است بدانید که در داخل عنصر<>service به هر تعداد remote object و یا به عبارت دیگر سرویس که بخواهیم میتوانیم معرفی کنیم؛ به شرط اینکه به هر کدام از آنها کانال خاصی اختصاص دهیم و بهطور کلی از عهده مدیریت چنین سیستمی برآییم. در چنین حالتی یک برنامه میزبان درخواستهای استفاده از چندین remote object را گرفته و handel میکند. عنصر channels تنظیمات مربوط به کانال یا کانالهای ارتباطی را در خود دارد. در اینجا فقط از یک کانال استفاده خواهیم کرد و به جای ایجاد کانال جدید، از کانالهای تعریفشده در Machine.config استفاده میکنیم. جهت اینکار از فیلد channel ref و سپس ازid کانال تعریف شده در machine.config استفاده میکنیم. فیلد port هم شماره پورتی که برنامه میزبان به آن گوش خواهد داد را مشخص میکند. فایل machine.config فایل XMLای است که تنظیمات ویژهای در سطح سیستم در آن قرار دارد، از جمله کانالهایی که به صورت پیشفرض در آن تعریف شدهاند این فایل در مسیر Microsoft.NET Frameuork CONFIG درSystem Root قرار دارد. با دیدن قسمتی که در آن کانال tcp client تعریف شده است، متوجه میشوید که تعریف کانال جدید در فایل پیکربندی برنامه میزبان کار چندان دشواری نیست. ضمناً علاوه براین کانال پنج کانال دیگر نیز در این فایل تعریف شدهاند که از کانال tcp client در پیادهسازی برنامه کلاینت استفاده خواهیم کرد. با وجود فایل پیکربندی، تمام کاری که برنامه میزبان باید انجام دهد، خواندن محتویات فایل پیکربندی و ایجاد کانال و قرار دادن آن در حالت listining جهت دریافت درخواستهای کلاینتها میباشد. برای انجام تمام این کارها کافیاست یک تابع static که در کلاس Remoting Configuration قرار دارد را فراخوانی کنیم و نام فایل پیکربندی را به عنوان آرگومان به آن بدهیم. برنامه میزبان را به هر صورتی که بخواهید میتوانید پیادهسازی کنید.