# Native Code > برنامه نویسی در Delphi > مقالات مرتبط با Delphi/Win32 >  برنامه نویسی شبکه ( راهنمای گام به گام Indy ) - بخش اول

## www2006

بسمه تعالی 
با عرض سلام خدمت همه دوستان عزیز  
هدف بنده از نوشتن این مقاله شروع بحثی درباره برنامه نویسی شبکه توسط Indy در محیط دلفی است.امیدوارم دوستان باتجربه تر در مفید تر شدن این نوشته همکاری کنند . 

بدون حاشیه مستقیم سراغ اصل مطلب میروم ...

*Indy TCP/IP server Component*
شاید فکر کنید که از قسمت سخت Indy Component شروع میکنیم ، در واقع درست فکر میکنید چون وقتی ساختن یک client را (در مقالات بعدی ) ببنید متوجه میشوید که ساخت یک client چقدر ساده است .

برای شروع ، یک پروژه جدید ( New Project ) ایجاد کرده ویک IdTcpServer component در آن قرار دهید .( این کامپوننت در برگه Indy Server قرار دارد و اولین کامپوننت است)
تنظیمات زیر را روی آن اعمال نمایید :
Property Name : Property Value
Active : True
DefaultPort : 1001
Greeting Text : hello 
خوب ... Tcp server شما آماده کار است! بدون اینکه حتی یک خط هم کد نوشته باشید . اگر برنامه خود را اجرا کنید فقط یک صفحه خالی نشان میدهد. برنامه را در حالت Run نگه دارید. برای تست سرور از telnet استفاده میکنیم ( خیلی ساده است ...! اگر مقاله را دنبال کنید)  
کافیست در Command Prompt تایپ کنید :c:\> telnet 127.0.0.1 1001که عدد 127.0.0.1 ip محلی شماست و 1001 هم شماره پورتی است که قبلا ست کرده اید. 
بعد از زدن کلید Enter پیغام hello از طرف سرور برای شما ارسال میشود .(پس ارتباط شما با سرور از پورت 1001 به درستی برقرار شده است .)
در ضمن فراموش نکنید که برنامه ای که برای سرور نوشته اید حتما باید run شده باشد ( یا بهتر بگویم باید در حال اجرا باشد .) 
پیغام hello که برای شما ارسال شده است در واقع همانGreeting Text property است که شما ست کرده اید پس هر پیغام دیگری میتواند باشد .

حالا میخواهم برنامه سروررا کمی توسعه دهم. میخواهیم سرور در برابر دستورات ما عکس-العمل نشان دهد .مثلا با تایپ دستور " Responde "، سرور پاسخ دهد که : 
" Ok ! I have Responded "

این در واقع اولین اجرای دستورات است .

برای این کار ابتدا مقدار CommandHandlersEnabled را برابر True قرار دهید . سپس روی CommandHandlers property دوبار کلیک کنید و در پنجره ای که باز میشود روی AddNew کلیک کنید . روی Item ای که اضافه میشود کلیک کرده و تنظیمات زیر را روی Property های آن اعمال کنید : 

Command : Responde
ReplyNormalText : ok! I have Responded 
برنامه را کامپایل و اجرا کنید ... سپس مجدد telnet را مانند قبل اجرا کنید و بعد از دریافت پیغام اولیه ، Respode را تایپ کرده و Enter را بزنید .خواهید دید که پیغام مورد نظر بعنوان پاسخ برگردانده میشود . 

در مقاله بعدی ابتدا کمی بیشتر در نحوه ایجاد ارتباط توسط سرور دقیق خواهیم شد و سپس سرور خود را توسعه خواهیم داد . 

موفق باشید ...

----------


## www2006

اجازه دهید قبل از اینکه برنامه سرور را توسعه دهیم ، نگاهی دقیقتر داشته باشیم به معماری داخلی Indy server . ( البته فرض می شود که خوانندگان عزیز با مفهوم MultiThreading آشنایی مقدماتی را دارند. ) بعد از این بخش شما تقریبا تمامی جنبه های رفتاری یک Indy Server را خواهید فهمید . 
تمام نود های فرزند یک TIDTcpServer دارای رفتار زیر هستند :
وقتی یک client به سرور متصل میشود ، thread ای که listener نام دارد (و کار آن هم دقیقا همان است که از نام آن بر می آید یعنی دایما در حال گوش دادن است تا ایجاد یک ارتباط جدید که توسط یک client ایجاد شده است را تشخیص دهد ) یک thread جدید ایجاد کرده و وظیفه Handle کردن تمام رخدادهای مربوط به این ارتباط را به آن thread واگذار میکند . پس در معماری داخلی یک سرور دو نوع thread وجود دارد : یکی Listener است که دایم در حالت انتظار برای ایجاد یک ارتباط جدید است و دیگری که بعد از ایجاد Connection بوجود می آید و کلیه وظایف ارتباطی بعهده اوست . 
این معماری زیاد جالب نیست چون client ها هر وقت که بخواهند (بدون توجه به اینکه ممکن است سرور مشغول رسیدگی به دهها درخواست رسیده دیگر باشد ) میتوانند به سرور متصل شوند .
زیاد نگران نباشید .... چون برای این که بتوان تعداد thread های ایجاد شده را کنترل کرد راه حلهایی وجو د دارد ... 
thread های نوع دوم ( آنهایی که listener نیستند ) را به دو شکل میتوان مدیریت کرد : 
TIdThreadMgrDefault and TIdThreadMgrPool 

قبل از اینکه در باره این دو مدل مدیریت thread ها و نحوه استفاده آنها توضیح دهم میخواهم خود IDThreadDefault و IDThreadPool را خیلی خلاصه معرفی کنم ...  
IDThreadDefault همان حالت پیش فرضی است که اگر ما هیچ تنظیمی را اعمال نکنیم ، اعمال میشود یعنی برای هر Connection یک thread بطور مجزا ایجاد میشود و هنگام خاتمه ارتباط (Disconnect) شدن از بین میرود .(Destroy) 
اما دومی (IDThreadPool) برای سرور هایی طراحی شده است که میخواهند بازدهی بالاتری داشته باشند . حافظه گرفتن و آزاد کردن آن عملی وقت گیر است به همین دلیل در حالت دوم استخری از thread ها (هرتعداد thread ای که شما تعیین کنید ) حافظه allocate میشود و در طول برنامه دیگر عمل گرفتن و آزاد کردن حافظه نخواهیم داشت . 
این کل مفاهیم Thread ها در Indy بود .(ساده و سریع) 
حتما میخواهید بدانید که چطور می توانید مدل thread ای را که میخواهند استفاده کنید را انتخاب کنید. خیلی ساده ... در برگه ی (Tab ( Indy misc شما هر دو نوع  
TIdThreadMgrDefault and TIdThreadMgrPool 
را مشاهده میکنید . کافیست هر کدام را که میخواهید روی فرم خود قرار داده و در
ThreadMgr Property ی سرور ( IdTCPServer1 ) آن را بعنوان مقدار وارد کنید . 

امیدوارم خسته نشده باشید ... مطالب بعدی ساده تر و عملی تر هستند .

موفق باشید ....

----------


## حامی2

با سلام و تشکر از مطالب مفیدتان
اما من یه سوال پیشرفته تر دارم و اینکه چگونه از یک کامپیوتر و از طریق شبکه می شود از روی یک کامپیوتر دیگر فایلی را باز کرد و نمایش داد مثلا فیلمی را از کا مپیوتر دیگری روی کامپیوتر خودتان ببینید ؟
این کار با استفاده از ویندوز ساده است اما با ابزار Indy می شود یا خیر؟

----------


## www2006

با سلام 
با استفاده از ابزارهای Indy  میتوان برای client ها فایلی را ارسال کرد و یا بر عکس .حتی می توان به برنامه های در حال اجرای کاربران هم دسترسی داشت و آنها را کنترل کرد. اما درباره اینکه بتوان وارد کامپیوتر کاربر شد و از فایلهای موجود در آن استفاده کرد(مثلا یک فایل تصویری را اجرا کرد)، من اطلاعی ندارم .

----------


## www2006

بعد از آشنایی کلی با مفاهیم Threading در Indy ، در این بخش می خواهم کمی بیشتر در باره TIDTcpServer Component صحبت کنم . 
یک سرور را میتوانیم در دو مد مختلف برنامه ریزی کنیم :

مد اول : 
مد اول استفاده از CommandHandlers است . نوشتن سرور در این حالت بسیار ساده است . این مد را با مثال توضیح میدهم تا فهم آن ساده تر و سریعتر باشد : 
فرض کنید که می خواهیم سروری داشته باشیم که در برابر دو دستور Hello و Add عکس العمل مناسب را انجام دهد . در برابر کلمه " Hello " ، کلمه " Hi " را برگرداند. اما دستور " Add " کمی متفاوت است چون میخواهیم با فرستادن چندین عدد به همراه دستور add حاصل جمع آنها را بدست آوریم .فرمت کلی دستور ارسالی ما به سرور به این شکل است :

add no1 no2 .... noN  

و سرور حاصل جمع " no1 + no2 + .... + noN " را برخواهد گرداند . 
مانند مثال اول یک TIDTcpServer روی فرم خود قرار دهید ( یا یک پروژه جدید باز کنید ویا از همان سرور قبلی استفاده کنید یعنی روی یک فرم دو کامپوننت TIDTcpServer نباشد ) . تنظیمات سرور دقیقا همانهایی است که در بخش اول ذکر شده است . حالا روی CommandHandlers دو بار کلیک کرده و در پنجره جدید *دو Item* جدید ایجاد کنید . برای Item اول مقادیر زیر را ست کنید : 
Command : Hello
ReplyNormal : Hi 
برای Item دوم هم مقدار Command را برابر کلمه " Add " قرار دهید و ...
حالا باید یه چند خطی کد نویسی کنید !  
در قسمت Event های Item دوم روی OnCommand دوبار کلیک کنید تا وارد محیط کدنویسی شوید : 



procedure TForm1.IdTCPServer1CommandHandlers1Command(ASender  : TIdCommand); 
*var* 
i:integer; 
f:float; 
*begin* 
f:=0; 
*for* i:=0 *to* ASender.Params.Count-1 *do* 
f:=f+strtofloat(ASender.Params[i]); 
ASender.Thread.Connection.Writeln(floattostr(f)); 
*end*;


به همین سادگی !
حالا برنامه را کامپایل و اجرا کنید . ( در حالی که برنامه شما Run است ) Telnet را با همان دو مقدار قبل ( یعنی با IP ی 127.0.0.1 و پورت 1001 ) فراخوانی کرده و سرور را تست کنید .

( ما تا حالا هیچ فکری برای Handle کردن error های احتمالی نکرده ایم ... چون فعلا هدف ما آموزش مفاهیم است نه نوشتن یک برنامه بی عیب و ایراد )

اگر مجدد به کدی که نوشته اید نگاه کنید مشاهده خواهید کرد که :
1- ما از یک Property ی ناآشنا به نام Asender استفاده کردیم .
2- Asender ،دارای یکسری Property است مثل Connection و یا Params .
3- نهایتا ما برای ارسال string به Tcp/Ip connection از متد Writeln استفاده کردیم . 

منظور ؟ : 
Asender در واقع همان Client ای است که به ما connect شده است . مطلبی که در باره Thread ها گفتم را که هنوز فراموش نکرده اید ؟ برای هر Client بلافاصله بعد از Connect شدن یک Thread جدید ایجاد میشود . در مورد بالا هم Asender در واقع نمایانگر client ای است که به سرور ما متصل شده است . Asender دارای Property های زیادی است که مهمترین آنها Connection است که درواقع پل ارتباطی ما با کاربر است .توسط آن ما میتوانیم یک String یا Integer ویا حتی یک Record را برای client ارسال کنیم .

در مقاله بعدی مد دوم را برای سرور بررسی میکنم و سعی خواهم کرد در باره client ها هم مطالبی رو بگم .با Indy همراه باشید ....

----------


## www2006

Indy یک پروژه OpenSource است . اگر در دلفی5 وجود ندارد می توانید آن را از :

http://www.indyproject.org/Sockets/D...Indy10.en.aspx

بطور رایگان دانلود کنید .

----------


## www2006

سلام  
همانطور که در انتهای بخش قبل قول داده بودم ، میخواستم درباره حالتی از سرور صحبت کنم که به طور اتومات دربرابر Command های کاربر عکس العمل نشان نمیدهد (مد دوم) ولی بنا به دلایلی این بحث را به آینده موکول میکنم . 
امروز درباره کامپوننت TIDTcpClient توضیح خواهم داد : 
اگر سه بخش قبل را فهمیده باشید ، فهمیدن این قسمت زیاد وقت شما را نمیگیرد.کافیست یک کامپوننت TIDTcpclient (در برگهIndy Client ، اولین کامپوننت است ) را روی فرم جدیدی که ایجاد کرده اید قرار دهید تا 80 درصد راه ساخت client را طی کرده باشید ..!
20 درصد باقیمانده موضوع این بخش از مقاله است . 
سروری که در بخش قبل ایجاد کردیم را به خاطر بیاورید .. دو دستور داشت به نامهای Hello و Add . میخواهیم client خود را برای برقراری ارتباط با این سرور تنظیم کنیم. 

روی فرم خود علاوه بر کامپوننت TIDTcpClient دو Button ویک Tlistbox هم قرار دهید . در این Listbox شما مقادیری که برای عمل جمع به سرور ارسال خواهید کرد را قرار خواهید داد . حالا باید مقادیر پورت ( Port ) و Host را برای TIDTcpClient ست کنید . 
Port همان است که برای سرور قرار داده اید ( در مثال ما 1001 است ). 
اما Host : 
اگر می خواهید برنامه client را در همان کامپیوتری اجرا کنید که سرور هم روی آن اجرا میشود مقدار Host را برابر 127.0.0.1 قرار دهید وگرنه مقدار آن را برابر با IP کامپیوتر سرور قرار دهید . 
ابتدا دستور Hello : 
روی اولین button دوبار کلیک کرده و کد زیر را وارد کنید :



*procedure* TForm1.Button1Click(Sender:TObject); 
begin 
with IdTcpClient1 do 
begin 
connect; 
Writeln('Hello'); 
ShowMessage(Readln); 
Disconnect;  
end; 

end;
 




حالا برنامه را اجرا کنید ( فراموش نکنید که همواره قبل از اجرای برنامه Client حتما باید برنامه سرور را Run کرده باشید وگرنه با پیغام " Socket Error #10061" مواجه خواهید شد ). اگر تمام مراحل را بدرستی طی کرده باشید باید پیغام "Ok, I have responded" دریافت کنید .



حالا نوبت دومین دستور است . اینبار روی دومین button دوبار کلیک کرده و قطعه کد ساده زیر را وارد کنید : 


*procedure TForm1.Button2Click(Sender:TObject);* 
var 


command: string; 
i:integer; 
begin 
command:='Add';  

for i:=0 to ListBox1.Items.Count -1 do command:=command+' '+ListBox1.Items[i]; 
with IdTcpClient1 do 
begin 
connect; 
Writeln(command); 
ShowMessage(Readln); 
Disconnect; 
end; 
end;  








تنها تفاوت آن با قبلی این است که در اینجا ما دستور add را با پارامترهایی که در listbox وارد کرده اید ترکیب کرده و حاصل را که یک String است برای سرور ارسال میکنیم. 








نکته :  

هنگام ارسال و دریافت یک پیغام بین Client و Server حتما به ترتیب متد های ارسال دقت لازم را داشته باشید .. مثلا اگر در سمت سرور چیزی مانند زیر داشتید : 

 
WriteStream (...); 
Writeln(...); 
ReadStream(...); 



در سمت کلاینت باید به این ترتیب باشد : 


ReadStream(...); 

ReadLn; 
WriteStram(...);


در حالات دیگر ( اگر ترتیب را رعایت نکنید ) قادر به برقراری درست ارتباط نخواهید بود. 



خوب ... کار Client هم تمام شد . در واقع مطالب مقدماتی ای که فکر میکردم برای شروع کار لازم دارید (تا حد امکان ساده و سریع ) تمام شد . 

منبع اصلی این نوشته را ( که البته بنده سعی کردم ترجمه ای ساده و خلاصه از آن داشته باشم ) می توانید در سایت Delphi3000.com پیدا کنید .



موفق باشید ...

----------


## یاسر مددیان

دوست عزیز نمی خوای ادامه بدی ؟ 
بیا یه مسنجر طراحی کنیم با دلفی .

با تشکر

----------


## siavashr

سلام.
من هم یاد میگیرم اگر کمکی هم از دستم بر بیاد درخدمت هستم.
سیاوش راد

----------


## www2006

> دوست عزیز نمی خوای ادامه بدی ؟


حتما ... البته با کمک دوستان ، چون مبحث خیلی گستردست .

با طراحی یک مسنجر ساده شروع کنیم ...

----------


## یاسر مددیان

عالیه
البته آقای سرباززاده پیش دستی کردن و یه سورس گذاشتن که از اینجا ازشون تشکر می کنم . من دارم دانلود می کنم .

مرسی .

----------


## www2006

بسمه تعالی 
بعد از مفاهیم مقدماتی و پایه ای ( که علیرغم سادگی اهمیت فوق العاده ای دارند ) میخواهم ایجاد یک Messenger ساده ( که شامل یک سرور است و می تواند با client خود تبادل اطلاعات کند(در اینجا فقط string)) را آغاز کنم . 
البته در همین ابتدای کار یاد آور شوم که زحمت Handle کردن Exception ها و توسعه برنامه گردن خوانندگان عزیز است چون نمیخواهم با کد های اضافه از خوانایی برنامه کاسته شود . 

ابتدا سمت سرور :  
مطابق شکل ، کامپوننت های زیر را روی فرم اولیه خود قرار دهید : 
TIDTcpServer و memo و edit و button 
https://barnamenevis.org/attach...1&d=1157878987 

حالا تنظیمات زیر را برای TIDTcpServer اعمال کنید : 
Active : true
DefaultPort : 5000 

یک متغیر سراسری به صورت زیر تعریف کنید : mythread : TIdPeerThread ;(دلیل استفاده من از این متغیر حفظ اطلاعات Connection ایجاد شده است . اگر کسی راه مناسبتری بلد است ،خوشحال میشوم من را هم راهنمایی کند .)
این متغیر را در متد onConnect سرور IdTcpserver1 مقدار دهی میکنیم :
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
mythread := athread ;
end;
 


سپس در قسمت event ها روی onExecute دو بار کلیک کرده و : 

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
begin
Memo1.Lines.Add(AThread.Connection.ReadLn()) ;
end;
 
نکته 1 - متد onExecute هرگاه که از طرف Client چیزی برای سرور ارسال شود اجرا میشود ، پس برای دریافت پیغام client مناسبترین متد است .

نکته 2 - اگر میخواهید هنگام connect شدن Client عمل خاصی انجام دهید ( مثلا چیزی مثل Authentication ) میتوانید از متد onConnect استفاده کنید که فقط یکبار و آن هم هنگامی که یک کاربر به سرور متصل میشود اجرا میشود .

نکته 3 - همانطور که قبلا هم گفتم هنگام اتصال کاربر به سرور یک Thread جدید ایجاد میشود ، Athread همان thread ایجاد شده است .


سرور آماده دریافت اطلاعات کاربر و نمایش آن در داخل Memo1 است . ( میتوانید با telnet آن را امتحان کنید)

برای ارسال پیغام خود به Client ( پیغامی که داخل Textbox نوشته اید ) کافیست کد زیر را در متد onClick دکمه ( Button1 ) وارد کنید :


procedure TForm1.Button1Click(Sender: TObject);
begin
mythread.Connection.WriteLn(Edit1.Text);
end;
 

خوب اگر از telnet برای امتحان صحت عملکرد سرور خود استفاده کنید خواهید دید که میتوانید به راحتی عملی مانند chat را با سرور داشته باشید . 
حالا نوبت client است . ایجاد client را در بخش بعد خواهم گفت . ( البته اگر عجله دارید خودتان شروع کنید چون با همین معلومات هم میتوان client ای طراحی کرد که با سرور ما کار کند.خیلی ساده است ..! ) 
موفق باشید ....

----------


## www2006

سمت کلاینت : 
روی فرم جدیدی که برای Client ایجاد کرده اید ، کامپوننت های زیر را ( مطابق شکل ) قرار دهید :  

https://barnamenevis.org/attach...1&d=1157975332 

TIDTcpClient و memo و button_send و edit_Message
*و*
Edit_ServerIP و Edit_ServerPORT و Button_Connect 

در اولین Editbox که Edit_ServerIP میباشد ، آدرس IP کامپیوتر سرور و یا نام NetBios ای آن را وارد میکنیم و داخل Edit_PORT هم شماره پورت . ( که البته مقدار آن را بصورت پیش فرض طوری قرار داده ام که با پورت 5000 از سروری که در همین کامپیوتر Run شده است ارتباط برقرار کند .) 
حالا روی Button_Connect دو بار کلیک کرده و :  

procedure TForm1.Button_connectClick(Sender: TObject);
begin
IdTCPClient1.Host := Edit_serverIP.Text ;
IdTCPClient1.Port := StrToInt(Edit_serverPORT.Text) ;
IdTCPClient1.Connect();
Button_connect.Enabled := False ;
end;
 
کار دستورات بالا واضح است( بعد از ست کردن Property های کلاینت ، ارتباط را با سرور برقرار میکنند ). آخرین دستور هم باعث جلوگیری از ارسال مجدد درخواست Connect میشود . 
تا الان کار ایجاد ارتباط بین برنامه Client و Server انجام شده است . فقط باید بتوانیم پیغامهای سرور را دریافت و پاسخ دهیم . کافیست Timer ای روی صفحه قرار دهیم (تب System ، اولین کامپوننت ) تا به محض ارسال پیغام از طرف سرور از آن مطلع شویم . کد زیر را هم در onTimer مینویسیم : 


procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False ;
try
Memo1.Lines.Add(' Server: ' + IdTCPClient1.ReadLn());
except on E:Exception do  Form1.Close ;
end ;
Timer1.Enabled := True ;
end;
 
نکته بسیار مهمی که وجود دارد این است که حتما از کامپوننت IDAntiFreeze ( تب Indy misc ، دومین کامپوننت )در کلاینت خود استفاده کنید . ( دلیل آن را میتوانید در لینک زیر پیدا کنید .)https://barnamenevis.org/showth...?t=9385&page=2  
خوب پیامهای سرور را هم دریافت کردیم ... حالا ارسال پیغام به سرور . 

روی Button_send دو بار کلیک کنید و : 


procedure TForm1.Button_sendClick(Sender: TObject);
begin
IdTCPClient1.WriteLn(Edit_message.Text);
end;
 

کار messenger ساده ما تمام شد .  
در ضمن کد های این برنامه را ( البته با تغییرات خیلی جزیی ) میتوانید از آدرس زیر دریافت کنید : https://barnamenevis.org/attach...1&d=1157975332 



موفق باشید ...

----------


## Mahdi_S_T

من یه برنامه دیدم که با  دلفی بود و این امکان رو داشت که به یاهو متصل بشه و وب کم کاربران رو ببینه در مورد این موارد هم مثال بزنید ممنون میشم.

----------


## Touska

> من یه برنامه دیدم که با دلفی بود و این امکان رو داشت که به یاهو متصل بشه و وب کم کاربران رو ببینه در مورد این موارد هم مثال بزنید ممنون میشم.


بابا کم کم به اونجا هم می رسیم ، بنده خدا خیلی دارن خوب توضیح میدن پله پله  :خجالت: 

اگه بتونید در کنارش توضیح مختصری از UDP  رو هم بدید کاملتر میشه  :کف کرده!:

----------


## www2006

> اگه بتونید در کنارش توضیح مختصری از UDP رو هم بدید کاملتر میشه


چشم .... حتما ...
فقط ما منتظر مطالب سایرین هم هستیم

----------


## یاسر مددیان

www2006 جان دستت درد نکنه . :خجالت:

----------


## seyed_farid

من میخوام سه کامپیوتر رو به هم شبکه کنم. دو تا بعنوان سرور و یکی بعنوان کلاینت. سرورها بصورت main و Standby باشند و برنامه کلاینت با هردوی آنها ارتباط داشته باشه. دوستان میتونند کمکی کنند در این زمینه؟

----------


## Touska

> من میخوام سه کامپیوتر رو به هم شبکه کنم. دو تا بعنوان سرور و یکی بعنوان کلاینت. سرورها بصورت main و Standby باشند و برنامه کلاینت با هردوی آنها ارتباط داشته باشه. دوستان میتونند کمکی کنند در این زمینه؟


ارتباط به چه شکل و چه جوری - بیشتر توضیح دهید ؟  :متفکر:

----------


## www2006

بسمه تعالی 





*مقدمه*
 
همانطور که می دانید پروتکل Udp یکی از دو پروتکل اصلی لایه انتقال ( Transprot layer ) در پروتکل TCP/IP است . پروتکل دیگر این لایه TCP می باشد (که قبلا کمابیش در باره نحوه کار آن صحبت کرده ام).در این مقاله میخواهم کمی در باره پروتکل Udp و نحوه ی استفاده از آن در دلفی صحبت کنم.




*تفاوتهای پروتکل های Tcp و Udp ( از نظر مفاهیم شبکه ) :* 
TCP: این پروتکل امکان ایجاد ارتباطات قابل اطمینان و اتصال گرا را فراهم می نماید. برخی از وظایف مربوط به این پروتکل به قرار زیر می باشد: 
• شکستن و تقسیم بندی داده ها و پشته های دریافتی از لایه بالاتر به بسته های TCP و ساخت مجدد پشته ها از بسته های TCP در مقصد . 
• حصول اطمینان از رسیدن بسته ها به مقصد . 
• بازبینی بسته ها و مرتب کردن آنها و کنترل خطا 
• کنترل جریان داده ها 
UDP: این پروتکل برای فراهم آوردن مکانیزمی جهت کاهش و کم کردن سرریز داده ها در انتقال اطلاعات بکار می رود و معمولا برای ارتباطاتی که نیاز به قابلیت اطمینان ندارند استفاده می شود. لایه انتقال در سطح بالای خود با لایه کاربرد در ارتباط است.داده های تحویلی به لایه کاربرد توسط برنامه های کاربردی قابل دریافت می باشد ، همچنین این برنامه ها می توانند با استفاده از APIها ( Application Program Interface ) مستقیما با لایه انتقال ارتباط برقرار کنند .  


*تفاوتهای پروتکل های Tcp و Udp ( در Indy ) :*

Tcp در یک نگاه : 
در ابتدا نگاهی داریم به جزییات Tcp . قبل از اینکه بتوانیم از طریق Tcp اطلاعاتی ردوبدل کنیم ، باید یک سوکت ایجاد کنیم ( به مجموعه یک آدرس IP و یک پورت ، یک سوکت گفته میشود مثلا 127.0.0.1:5000 ) . به این طریق میتوان یک ارتباط Point to Point ایجاد کرد که توسط آن یک مسیر دو طرفه برای انتقال داده ها بین نود ها ایجاد میشود . لازمه ایجاد یک سوکت وجود یک Client و یک Server میباشد ( سرور سوکتی را پیشنهاد می دهد و Client از آن استفاده میکند) . بعد از موفقیت آمیز بودن مقدمات کار ، یک مسیر دو طرفه که کاملا مستقل از یکدیگر هستند برای ارتباط سرور و کلاینت ایجاد میشود . کاربران گاهی به این نکته توجه نمیکنند که واسط دریافت در Indy توسط TidTcpServer و TidTcpClient کاملا جدا از هم میباشد ، بنابراین برای ایجاد یک دیالوگ ( Dialog ) بین Client و Server که سرور شروع کننده آن است ، کمی مهارت لازم است .
هنگام مبادله اطلاعات باید به این نکته توجه کنیم که Tcp بر اساس data *Stream* کار میکند نه data *Block* . یعنی فریمها ارسال میشوند نه یک بلاک از اطلاعات . در ضمن ساختار Packet های ارسالی مخفی از دید کاربر است . مکانیزم های انتقالی هم در اینجا استفاده میشوند تا با الحاق داده ها با یکدیگر ، بسته های IP بزرگتری بسازند تا از Overhead مسیر بکاهند .
هنگامی که در Indy شما از توابع TidTcpClient.Writeln یا TidTcpClient.WriteBuffer برای فرستادن یک* Block* از داده ها استفاده میکنید ، نمیتوانید اطمینان داشته باشید که گیرنده دقیقا همان چیزی را دریافت میکند که شما فرستاده اید . شاید بلاکهای اضافه ای را نیز دریافت کند یا اینکه بلاکی را با یکسری اطلاعات اضافه تر دریافت کرده باشد . (چون در طی مسیر یکسری سرآیند ها به اطلاعاتی که شما فرستاده اید اضافه میشود . بحث در باره دلایل این کار خارج از موضوع کار ماست.)


UDP ? UDP !
برخلاف Tcp پروتکل Udp یک *Block* از داده ها را ارسال میکند . سایز این بلاک تا حداکثر 64 کیلو بایت میتواند باشد . اگر هنگام ارسال یک بلاک در این حالت ، قسمتی از بسته IP درست ارسال نشود کل بسته دور انداخته میشود و باید مجدد ارسال شود .
در هنگام استفاده از udp در Indy شما باید سایز بافر را در کامپوننت udp برابر با طول بزرگترین بلاکی که میخواهید ارسال کنید قرار دهید . 
بر اساس تعریف استاندارد Udp ، برای ایجاد یک ارتباط بین دو نود چیزی شبیه سوکت وجود ندارد . هر کدام از انتقال بلاکها مقصد خاص خود را دارند . پس تعریف client و server با آنچه در Tcp دیدیم تفاوت دارد . یک سرور udp پورتی را ست میکند و تمام device های تحت شبکه از آن طریق میتوانند بلاکهای داده ی udp مورد نظرشان را به آن ارسال کنند . در اینجا فقط UdpSender و UdpReciver وجود دارد ولی Indy با تعریف TIdUDPClient و TIdUDPServer کمی مبهم عمل کرده است . هر دو این کامپوننتها میتوانند UdpBlock ها را بنویسند (Write ) اما همانطور که گفته شد تنها TIDUDPServer توانایی تعریف پورت را دارد . TIDUDPClient در قسمت Properties خود هم Host دارد و هم Port که این دو ، مقصد بلاکهای ارسالی توسط این client را مشخص میکنند و در طول اجرای برنامه قابل تغییر هستند .


با توجه به نحوه عملکرد الگوریتم انتقال UDP ، میتوانیم به راحتی یک UDP Broadcast را در شبکه داشته باشیم : پیغامی که برای تمام گیرنده هایی که در شبکه یک پورت باز دارند ارسال شود .


بر اساس ساختار اطلاعات ، UDP از محدوده اطلاعات در طی انتقال داده ها حفاظت میکند . به همین دلیل در TIDUDPServer یک event ای وجود دارد که توانایی دسترسی اختصاصی به هر یک از بلاکها را فراهم میکند . هر بلاک میتواند از یکی از Device های شبکه آمده باشد ، پس Event مذکور با استفاده از "binding " اطلاعات فرستنده ی بلاک را نگه می دارد .


پیشنهاد میکنم برای تکمیل و تفهیم این موضوع حتما به *Chat application* مراجعه کنید .

*منابع :*

http://www.parsstyle.com/instruction...oints.php?id=2
http://delphi.about.com/od/adptips2005/qt/udpvstcp.htm 


موفق باشید ...

----------


## seyed_farid

> من میخوام سه کامپیوتر رو به هم شبکه کنم. دو تا بعنوان سرور و یکی بعنوان کلاینت. سرورها بصورت main و Standby باشند و برنامه کلاینت با هردوی آنها ارتباط داشته باشه. دوستان میتونند کمکی کنند در این زمینه؟


در این برنامه کار به این صورته که همیشه یکی از سرورها بعنوان سرور فعاله و دیگری بعنوان سرورStandby و کلاینت با سرور فعال تبادل اطلاعات میکنه و سرور St/by در صورتیکه اشکالی تو سرور اصلی پیش بیاد میاد تو مدار و حالا اون میشه سرور فعال و با کلاینت ارتباط برقرار میکنه. ارتباطشون هم از طریق پورت شبکه باید باشه. من برنامه ای دارم که روی سرورها نصب میشه و برنامه دیگری هم روی کامپیوتر کلاینت نصب میشه و سیستم اصلی و قطعات و مدارات سویچ روی سرورها نصب میشه و کلاینت در جای دیگری اطلاعات رو به سرور ارسال میکنه و سرور دستورات لازم رو به قطعات جانبی که از طریق پورت پرینتر متصل میشن میفرسته.
من با Tcpserver  و Tcpclient  کار رو شروع کردم . میخوام ببینم این کمپوننت جواب کارم رو میده یا از چیز دیگری استفاده کنم بهتره؟ :متفکر:

----------


## Touska

ای ول به شما به این کاری که شما می کنید  در اصطلاح می گن Load Balancing که با ابزارهای Indy نیز میشه اینو پیاده کرد.

ببینید شما اگر Thread Connection ها خود را در حافظه نگه داشته باشید می توانید آنها را در یک memory Stream 

ذخیره کرده و به سرور Standby خود بفرستید و آنجا انها را لود نمایید.

به شرطی که که دو سرور یک Address IP داشته و در یک پورت باز شده باشند و در مواقع اظطراری آن یکی به شبکه متصل شود.

در غیر اینصورت باید Connetion های خود را به اطلاع آن یکی برسانید که از دوباره از سمت سرور درخواست Connect داده شود.

موفق باشید  :چشمک:

----------


## seyed_farid

با تشکر از توسکای عزیز
دو کامپیوتر سرور باید همیشه در مدار باشند و همدیگر و کلاینت را چک کنند و به محض ایراد تو یکی دیگری وارد مدار بشه. این دو باید دو آدرس جدا داشته باشند تا بتونند با هم تبادل داشته باشند.
تو این مورد شما کاری کرده اید و آیا نمونه ای دارید یا نه؟

----------


## Touska

> با تشکر از توسکای عزیز
> دو کامپیوتر سرور باید همیشه در مدار باشند و همدیگر و کلاینت را چک کنند و به محض ایراد تو یکی دیگری وارد مدار بشه. این دو باید دو آدرس جدا داشته باشند تا بتونند با هم تبادل داشته باشند.
> تو این مورد شما کاری کرده اید و آیا نمونه ای دارید یا نه؟


به این شکل کار نکردم - ولی مقاله ای در رابطه به Application Server ها داشتم مثل Oracle

اگر پیدا کردم براتون می فرستم. (در مورد Load Balancing)  :لبخند گشاده!:

----------


## seyed_farid

ممنونم که کمک میکنید. اگه بتونید زحمت بکشید برام بفرستید به ایمیلم.
من این برنامه رو شروع کردم . ببینید این چت چطوره؟

----------


## www2006

> من این برنامه رو شروع کردم . ببینید این چت چطوره؟


چرا Port هات (بصورت پیش فرض) سه تا عدد متفاوت دارند ؟ 
کلا برای سرور و کل کلاینت ها در این مدل برنامه ها یک شماره ی منحصر بفرد و یکتا در نظر میگیرند . 
(البته من از ایده ی شما خبر ندارم،اگر توضیح بدی ممنون میشم)

----------


## seyed_farid

خدمت شما عرض کنم که این پورتها برای سرور در حقیقت پورتی هست که بگوش هست و برای کلاینت پورتی هست که میخواهد چیزی به آن پورت بفرستد و هر کسی روی پورت سرور چیزی بفرستد میگیرد و نیاز به کانکت شدن به سرور فعال هم ندارند و فقط موقع ارسال پیام گیرنده باید فعال باشد وگرنه خطا میدهد.

----------


## moeinelec

سلام به دوستان عزیز من این کد را وارد کردم 
(IdCmdTCPServer1TIdCommandHandler1Command(ASender: TIdCommand
بعد بهم خطا میده 
' Undeclared identifier: 'TIdCommand
فکر می کنم مشکل از namespace باشه کسی کمک مکنه؟ ممنون

----------


## vcldeveloper

> بعد بهم خطا میده 
> ' Undeclared identifier: 'TIdCommand


یونیت IdTCPServer را به لیست uses اضافه کنید.

----------


## moeinelec

اقای کشاورز اینها توی لیست uses هست ولی بازم error میده
 IdComponent, IdTCPServer, IdExplicitTLSClientServerBase

----------


## barat121

یعنی این تاپیک تموم شده و به نتیجه لازم هم رسیده ؟

----------


## spicirmkh

سلام

دوستان من می خواهم مرحله به مرحله indy در دلفی 2007 تست و اجرا کنم
که متاسفانه بعضی از کامپونت تغییر نام داده یا جابجا شدهاند از نظر مکانی یا دستوراتی که مدهم پیغام خطا میدهد مثل IdTcpClient1.Readln راهی وجود دارد بدون اینکه دلفی 7 نصب کنم در دلفی 2007 این دستورات اجرا کنم 

با تشکر

----------


## attarizi

بچه ها خدایی دمتون گرم انقدر چیز یاد گرفتم که دارم پس میوفتم

----------


## baby_tanhaa

حالا اگه بخوایم به جای string یه فایل بفرستیم مثلا یه عکس چیکار باید بکنیم ؟؟
میشه یکی توضیح بده؟؟

----------


## vcldeveloper

> حالا اگه بخوایم به جای string یه فایل بفرستیم مثلا یه عکس چیکار باید بکنیم ؟


فایل رو در یک stream میریزید و با متد WriteStream آن را به سرور ارسال می کنید.

----------


## winer3549

سلام
میخواستم بدونم که میشه 4 یا 5 تا کلاینت هم داشت ؟؟؟

----------


## vcldeveloper

> میخواستم بدونم که میشه 4 یا 5 تا کلاینت هم داشت ؟؟؟


در تعداد کلاینت محدودیتی وجود نداره، جز سخت افزار و  توان شبکه موجود.

----------


## mms_4004

سلام مرسی از مطالب مفیدتون دارم می خونم اما چون همیشه من عجولم می خواستم ببینم که با همین روش و استفاده از Indy میشه با استفاده از مودم و خط تلفن برنامه Client/Server رو اجرا کرد؟ اگر میشه کمی توضیح دهید. متشکر.

----------


## vcldeveloper

> می خواستم ببینم که با همین روش و استفاده از Indy میشه با استفاده از مودم و خط تلفن برنامه Client/Server رو اجرا کرد؟


Indy نیاز به یک بستر شبکه داره. اگر با مودم و خط تلفنتان یک شبکه کامپیوتری بوجود آوردید (مثلا یک RAS Server درست کنید)، یا به یک شبکه کامپیوتری متصل شدید (مثل اتصال به اینترنت به شیوه Dial-up)، می تونید از indy برای اون کار استفاده کنید.

----------


## hedayat44

با تشكر
خواهشمند است ادامه دهيد.

----------


## ParsaNM

ممنون دوستان ...
خيلي خوب و کامل بود ... خيلي استفاده کردم ...
خوب يک مشکل ايجاد شده ... ! در دلفي 2010 بعضي از property ها حذف شده و کلا اين کامپوننت ها منطقشون عوض شده ... مثلا براي اجراي TIDTCPServer مي بايست حتما onexecute نوشته شده یاشد (البته حتي خالي) شما در اين رابطه چيزي مي دونين ..؟

----------


## ایمان ناصری نیا

با تشکر از راهنمایی های دوستان
دوستان اگه می تونستن اطلاعاتشونو بصورت مستند (pdf,word,...) در بیارن و هر کسی وظیفه تکمیل یه قسمتی به عهده میگرفت فکر میکنم نتیجه بهتری میگرفتیم

----------

