ورود

View Full Version : سوالی در خصوص ReadLn و WriteLn



مهران رسا
پنج شنبه 16 اردیبهشت 1389, 19:31 عصر
با سلام.

در کتاب آموزش Indy 10 یک همچین کدی برای سمت مشتری (Client) نوشته شده :


WriteLn('ZipCode ' + memoInput.Lines[i]);
s := ReadLn;

در واقع همونطور که مشخص هست با استفاده از متد WriteLn یک پیام روی خط نوشته میشه و دقیقاً در خط بعدی جواب از سمت Server دریافت شده و در متغیر s قرار میگیره .

قبلاً زمانی که از Winsock استفاده میکردم ، رویداد هایی رو در اختیارم قرار میداد که با استفاده از اونها میشد پیغام های دریافتی از سمت سرویس دهنده رو مدیریت کرد . اما دیدن این 2 خط کد کمی برام تعجب برانگیزه ! با توجه به پارامترهای مختلفی ازجمله سرعت ،چطور ممکنه بدون استفاده از حلقه های تکرار جواب ارسال شده از سرور رو در همون لحظه دریافت کرد ؟
آیا وقفه ی خاصی در برنامه ایجاد میشه ؟

vcldeveloper
پنج شنبه 16 اردیبهشت 1389, 22:47 عصر
قبلاً زمانی که از Winsock استفاده میکردم ، رویداد هایی رو در اختیارم قرار میداد که با استفاده از اونها میشد پیغام های دریافتی از سمت سرویس دهنده رو مدیریت کرد . اما دیدن این 2 خط کد کمی برام تعجب برانگیزه ! با توجه به پارامترهای مختلفی ازجمله سرعت ،چطور ممکنه بدون استفاده از حلقه های تکرار جواب ارسال شده از سرور رو در همون لحظه دریافت کرد ؟
آیا وقفه ی خاصی در برنامه ایجاد میشه ؟
برای اینکه این موضوع رو متوجه بشید، باید بدونید که Indy به صورت Blocking mode با شبکه کار میکنه، در حالی که WinSock به صورت non-blocking هست. منظور این هست که Indy به صورت Asynchronous عمل نمیکنه، وقتی شما یک داده ایی را از سرور درخواست می کنید، Thread شما تا زمان دریافت اون داده از سرور، منتظر میمونه. این روش مزیت هایی داره، که عمده ترین اون ساده شدن کد نوشته شده توسط برنامه نویس هست. البته اگر این انتظارها طولانی باشه، اون وقت مجبورید که از Indy در Thread جداگانه ایی استفاده کنید، تا موجب Freeze شدن برنامه شما نشه.

در راهنمای Indy درباره Blocking Mode مفصلا توضیح داده شده.

مهران رسا
پنج شنبه 16 اردیبهشت 1389, 22:57 عصر
الآن متوجه شدم در کلاینت برای مدیریت تمامی response های سرور میشه از Timer استفاده کرد . آیا راه درستیه ؟

vcldeveloper
شنبه 18 اردیبهشت 1389, 14:41 عصر
الآن متوجه شدم در کلاینت برای مدیریت تمامی response های سرور میشه از Timer استفاده کرد .
چرا Timer؟ چه کدی نوشتید؟

مهران رسا
شنبه 18 اردیبهشت 1389, 15:57 عصر
چرا Timer؟ چه کدی نوشتید؟
در واقع کنترل TCPServer رویدادی با نام OnExecute داره که تا زمان جاری بودن ارتباط دائماً در حال اجرا شدن هست . پس برای دریافت پیغام مشتریان از این رویداد استفاده میکنیم . اما در TCPClient همچین رویدادی وجود نداره .


procedure TForm1.Timer1Timer(Sender: TObject);
var
ServerMessage: string;
begin
ServerMessage := IndyClient.IOHandler.ReadLn;
end;

vcldeveloper
شنبه 18 اردیبهشت 1389, 16:11 عصر
در واقع کنترل TCPServer رویدادی با نام OnExecute داره که تا زمان جاری بودن ارتباط دائماً در حال اجرا شدن هست . پس برای دریافت پیغام مشتریان از این رویداد استفاده میکنیم . اما در TCPClient همچین رویدادی وجود نداره
این به خاطر ماهیت سرور و کلاینت هست. سرور یعنی اونی که درخواست دریافت میکنه، و به درخواست پاسخ میده. کلاینت هم اونی هست که درخواست ارسال میکنه، و جواب درخواستش را دریافت میکنه.

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

اما اگر سرور شما برای خودش، بدون اینکه درخواستی از کلاینت دریافت کرده باشه، پیامی برای کلاینت بفرسته، اون وقت دیگه جای سرور و کلاینت عوض شده؛ یعنی در اون حالت دیگه سرور شما نقش یک کلاینت رو بازی میکنه، و کلاینت شما نقش سرور رو. پس اگر همچین حالتی در برنامه دارید، باید در هر دو سمت یک IdTcpServer و یک IdTCPClient داشته باشید. البته میشه بدون استفاده از دو کامپوننت هم برای IdTCPClient پیام ارسال کرد، و با استفاده از همون Timer یا حلقه، آمدن پیام را بررسی کرد، ولی بهتره از دو کامپوننت استفاده کنید.

مهران رسا
شنبه 18 اردیبهشت 1389, 16:45 عصر
پس با این تفاسیر ، استفاده از دستورات sequential در کنار کنترل IdAntiFreeze جواب سوال من هست .

WriteLn('ZipCode ' + memoInput.Lines[i]);
s := ReadLn;

آقای کشاورز خیلی ممنون .