پروتکل Transmission Control Protocol) TCP) یک پروتکل جریان گرا، ارتباط گرا، قابل اعتماد و نظیر به نظیر می باشد. ارتباط TPC همانند ارتباط تلفنی می باشد. به عنوان مثال شما (سرویس گیرنده) به منزل دوست خود (سرویس دهنده) زنگ می زنید. در صورتیکه دوست شما در منزل باشد تلفن را برداشته و با یکدیگر شروع به صحبت می کنید (نظیر به نظیر، جریان گرا، قابل اعتماد) و در انتها شما و دوستتان گوشی تلفن را قطع کرده (ارتباط گرا) و به ارتباط خود خاتمه می دهید. به عنوان مثال پروتکل HTTP از TCP استفاده می کند.TCP از IP به عنوان پروتکل شبکه استفاده می کند. IP یک پروتکل datagram (بسته های داده) گرا و Best-Effort (بسته های داده بصورتی فرستاده می شود که تحویل و صحت آن تضمین نمی گردد) می باشد.
در این مقاله یک مثال کوچک و ساده در مورد چگونگی برقراری ارتباط بین سرویس دهنده و سرویس گیرنده مورد بررسی قرار می گیرد. این مثال از دو بخش تشکیل شده است. بخش سرویس دهنده و بخش سرویس گیرنده.
کلاسهای مورد نیاز
در این مثال تنها دو کلاس اصلی بکار برده شده است. در سمت سرویس گیرنده، از کلاس System.Net.Sockets.TcpClient و در سمت سرویس دهنده از کلاس System.Net.Sockets.TcpListener استفاده می گردد. بطور کلی در سمت سرویس گیرنده یک TcpClient به سرویس دهنده متصل می شود. سپس با یک کانالی (جریان) که به سرویس دهنده اختصاص داده شده است اعمال مربوطه انجام می پذیرد.
// اتصال به سرویس دهنده ۱۲۷٫۰٫۰٫۱:۸۰۸۰ TcpCleint client = new TcpClient(“۱۲۷.۰.۰.۱″, ۸۰۸۰); // گرفتن کانال ارتباطی برای ردوبدل کردن داده ها NetworkStream ns = client.GetStream(); // قطع ارتباط با سرویس دهنده client.Close();
سمت سرویس دهنده شامل مراحلی بیشتری می باشد، اما صورت کلی کد به همان صورت کد سرویس گیرنده شبیه می باشد. ابتدا باید یک درگاه محلی را به TcpListener اختصاص داد. در صورتیکه سرویس گیرنده به سرویس دهنده متصل شود به شما یک socket برگردانده می شود. با استفاده از این socket شما می تواند یک کانال ارتباطی (جریان) ایجاد نمایید.
// برروی پورت ۸۰۸۰ listener ایجاد یک TcpListener listener = new TcpListener(8080); listener.Start(); // انتظار بمنظور دریافت درخواست از سمت سرویس گیرنده Socket server = listener.AcceptSocket(); // ایجاد یک کانال برای ردوبدل کردن داده ها NetworkStream ns = new NetworkStream(server); // قطع ارتباط از سرویس گیرنده server.Close();
قالب دستورات
در این مثال دستورات با استفاده از (دستورات با Enter از هم جدا می شوند) از یکدیگر تمیز داده می شوند. در صورتیکه سرویس گیرنده دستور “GET” را اجرا نماید پیغام “Hello World” برای او ارسال شده و در صورت ارسال دستور “EXIT” عبارت “BYE” برای سرویس گیرنده فرستاده شده و ارتباط قطع می گردد.
سرویس دهنده
در دنیای واقعی سرویس دهنده از دو قسمت اصلی تشکیل می شود. قسمت Functional Layer و دیگری Commad Processor. قسمت پردازشگر دستورات واسطی بین لایه ارتباطی و Functional Layer می باشد. لایه ارتباطی درخواست خود را به لایه پردازشگر دستورات ارسال می کند این لایه درخواست را به لایه Functional ارسال کرده و پس از دریافت جواب از لایه Functional آنرا به لایه ارتباطی می فرستد. سرویس دهنده ها معمولا به صورت سرویس های سیستم عامل اجرا می شوند. در این مثال سرویس دهنده ما تنها یک لایه داشته و به عنوان یک برنامه کنسول اجرا می گردد.
Console.WriteLine(“Intitializing Server …”); TcpListener listener = new TcpListener(8080); listener.Start(); Console.WriteLine(“Server initialized, waiting for incomming connections …”); Socket s = listener.AcceptSocket(); // ایجاد یک جریان برای ارتباط NetworkStream ns = new NetworkStream(s); StreamReader r = new StreamReader(ns);
listener برروی پورت ۸۰۸۰ آماده دریافت درخواست سرویس گیرنده ها می باشد. متد AcceptSocket در زمان اتصال سرویس گیرنده یک socket را برمی گرداند. این متد برنامه را تا زمان دریافت درخواست معلق می کند. در صورت نیاز می توان از یک نخ برای این منظور استفاده نمود. در ادامه کانال ارتباطی لازمه برقرار می گردد و از کلاس StreamReader بمنظور دریافت داده ها از این کانال استفاده می شود. در این قسمت فرمانهای صادر شده از سوی سرویس دهنده باید بررسی و پاسخ مورد نظر به آن داده شود.
bool loop = false; while (!loop) { // خواندن یک خط کامل string command = r.ReadLine(); string result; Console.WriteLine(“Executing remote commad: ” + command); switch (command) { case “GET”: result = “Hello World !”; break; // خاتمه ارتباط case “EXIT”: result = “BYE”; loop = true; break; // دستور نامعتبر default: result = “ERROR”; break; } if (result != null) { Console.WriteLine(“Sending result: ” + result); // به انتهای پیغام پیغام CRLF افزودن result += “\r\n”; // تبدیل رشته به آرایه ای از بایتها Byte[] res = System.Text.Encoding.ASCII.GetBytes( < BR > result.ToCharArray()); // ارسال نتیجه به سرویس گیرنده s.Send(res, res.Length, 0); } }
در صورتیکه دستور GET در یافت شود سرویس دهنده پیغام Hello World را صادر کرده و ادامه دستورات پردازش می گردد. در صورت صدور دستور ناشناخته نیز پردازش دستورات ادامه می یابد. در صورت دریافت دستور EXIT پردازش دستورات خاتمه یافته و در ادامه ارتباط با سرویس گیرنده قطع می شود.
Console.WriteLine(“Clearing up server …”); s.Close(); Console.Write(“Press return to exit”); Console.ReadLine();
سرویس گیرنده
سرویس گیرنده تا حدودی از سرویس دهنده پیچیده تر می باشد. سرویس گیرنده شامل دو قسمت می باشد: واسط کاربر (که یک برنامه کنسول ساده است) و پردازشگر دستورات که شامل عناصر ارتباطی می باشد. در ابتدا پردازشگر دستورات مورد بررسی قرار می گیرد. برای اینکار ابتدا یک interface ایجاد می کنیم. استفاده از interface قابلیت انعطاف پذیری بیشتری در مورد استفاده از پروتکل های دیگر به شما می دهد. در این حالت سرویس گیرنده تنها اشیاعی را می پذیرد که واسط مورد نظر را پیاده سازی کرده باشند. این عمل باعث استقلال سرویس گیرنده از پروتکل ارتباطی می گردد.
public interface CommandProcessor { // یک دستور را اجرا کرده و حاصل را برمی گرداند // باشد پردازش دستورات باید متوقف گردد false در صورتیکه خروجی آن bool Execute(string command, ref string result); }
در ادامه یک کلاس با نام TCPClientCommandProcessor ایجاد می گردد. این کلاس واسط CommadProcessor را پیاده سازی می نماید. این کلاس شامل ۳ متد و یک سازنده می باشد. متد Connect وظیفه اتصال بر سرویس دهنده را برعهده دارد. بوسیله متد DisConnect ارتباط با سرویس دهنده قطع گشته و با متد Execute فرمانهای مورد نظر به سرویس دهنده ارسال می گردد.
public class TCPClientCommandProcessor : CommandProcessor { // آدرس سرویس دهنده string host = null; // پورت سرویس دهنده private int port = -1; // واسط ارتباطی private TcpClient client = null; // جریان خروجی داده private NetworkStream outStream = null; // جریان ورودی داده private StreamReader inStream = null; public TCPClientCommandProcessor(string host, int port) { this.host = host; this.port = port; this.Connect(); } // اتصال به سرویس دهنده public void Connect() { Console.WriteLine(String.Format(“Connecting to {0}:{1} …”, this.host, this.port) ); this.client = new TcpClient(this.host, this.port); this.outStream = this.client.GetStream(); this.inStream = new StreamReader(this.outStream); Console.WriteLine(String.Format(“Connected to {0}:{1}”, this.host, this.port) ); } // قطع ارتباط با سرویس دهنده public void DisConnect() { if (this.client != null) { this.client.Close(); Console.WriteLine(String.Format(“Connection closed: {0}:{1}”, this.host, this.port) ); } } // اجرای دستورات public bool Execute(string command, ref string result) { bool ret = true; command += “\r\n”; Byte[] cmd = System.Text.Encoding.ASCII.GetBytes( command.ToCharArray() ); // ارسال درخواست this.outStream.Write(cmd, 0, cmd.Length); // دریافت پیام result = this.inStream.ReadLine(); ret = !result.Equals(“BYE”); return ret; } }
واسط کاربر سرویس گیرنده
واسط کاربر سرویس گیرنده یک برنامه کنسول ساده می باشد. در این برنامه یک شئ از کلاس TCPClientCommandProcessor ایجاد شده و اعمال مربوطه انجام می گردد.
Console.WriteLine(“Initializing client …”); TCPClientCommandProcessor proc = new TCPClientCommandProcessor(“۱۲۷.۰.۰.۱″, ۸۰۸۰); string result = “”; string cmd = null; while (!result.Equals(“BYE”)) { Console.Write(“Command : “); cmd = Console.ReadLine(); proc.Execute(cmd, ref result); Console.WriteLine(result); } Console.WriteLine(“Closing connection…”); proc.DisConnect(); Console.Write(“Press return to exit”); Console.ReadLine();
برگرفته ار کتاب C#.NET Web Developer’s Guide انتشارات SYNGRESS