PDA

View Full Version : رويداد رسيدن پيام در indyclient



baby_tanhaa
سه شنبه 17 اردیبهشت 1387, 11:03 صبح
تو indyserver از طريق رويداد execute ميشه فهميد كه داده اي از كلاينت رسيده
اما ميخوام بدونم تو indyclient چه رويدادي واسه اينكار داريم
لطفا يكي راهنماييم كنه

babak_delphi
سه شنبه 17 اردیبهشت 1387, 14:57 عصر
در مثالهای INDY این کار را با استفاده از یک تایمر و کنترل ورودی انجام می دهد
اما به نظر من که کار جالبی نیست
من فقط این راه را بلدم از دوستان اگر کسی راه بهتری می داند لطفا معرفی کند.

baby_tanhaa
سه شنبه 17 اردیبهشت 1387, 16:23 عصر
ممنون بابك جان ولي فكر كنم اون جوري پيچيده ميشه و اگه در هر دو طرف برنامه هم از indyclient و هم از indyserver استفاده كنم رحتتر باشه
دوستان راه بهتري به نظرشون نميرسه ؟؟؟
فكر ميكردم دلفي زبان قوي اي هست ولي واقعا اينهمه ضعف جاي سئوال نداره ................

vcldeveloper
چهارشنبه 18 اردیبهشت 1387, 00:44 صبح
Off-topic:


فكر ميكردم دلفي زبان قوي اي هست ولي واقعا اينهمه ضعف جاي سئوال نداره ................
خواهشا هر بار هر جا گیر کردید، مطلب بی ربط ننویسید! جدیدا هر کی میاد کم اطلاعی، بی اطلاعی، کج فهمی یا هر چیز دیگه خودش رو به ابزاری که استفاده میکنه نسبت میده! یکی برنامه می نویسه و Access Violation میگیره، میگه دلفی ایراد داره! یکی نمیتونه یک کلمه رو در سورس Replace کنه، میگه دلفی ایراد داره، یکی وقت نمیزاره با Indy و نحوه کارش آشنا بشه، میگه دلفی ضعف داره! یکی توی سایت سوال می پرسه، جواب نمیگیره، میگه دلفی گیر داره! دلفی یا تیم سازنده آن مصون از اشتباه و خطا نیستند، ولی وظیفه هم ندارند بجای شما و امثال شما Document ها و Sample های مربوط به یک موضوع خاص را برای شما بخونند و خط به خط هم براتون تشریح کنند!
این چند وقته هر کی سوالش به جواب نمی رسه، یا از کاربران سایت شاکی هست، یا از دلفی. ماشاء احتمال اینکه ایراد از خودش باشه رو هم نمیده. نمی دونم واقعا اینجور پست ها زیاد شده، یا من این روزها زیاد چشمم به این چیزا میافته!

Touska
چهارشنبه 18 اردیبهشت 1387, 12:34 عصر
ممنون بابك جان ولي فكر كنم اون جوري پيچيده ميشه و اگه در هر دو طرف برنامه هم از indyclient و هم از indyserver استفاده كنم رحتتر باشه
دوستان راه بهتري به نظرشون نميرسه ؟؟؟
فكر ميكردم دلفي زبان قوي اي هست ولي واقعا اينهمه ضعف جاي سئوال نداره ................


من در مورد مشکل شما یک Sample با Source کامل در سایت قرار دادم .

لینک (http://barnamenevis.org/forum/showthread.php?t=52437&highlight=Chat)

کافی بود جستجو می نمودید.

baby_tanhaa
پنج شنبه 19 اردیبهشت 1387, 09:09 صبح
جناب كشاورز چرا داغ ميكني از قديم گفتن تا نباشد چيزكي مردم نگويند چيزها من قبلا با وي بي كار ميكردم كه گفتن دلفي بهتره اومدم سراغ دلفي اما مثلا همين موردو ميبينم تو وي بي خيلي راحت ميشه انجام داد درصورتي كه از هردلفي كاري پرسيدم راه حل درستي براش تو دلفي پيدا نكرد وقتي ميگن يه زبان خيلي قدرتمنده ديگه نبايد همچين چيزايي توشديده بشه بدميگم !!!

vcldeveloper
پنج شنبه 19 اردیبهشت 1387, 18:24 عصر
وقتي ميگن يه زبان خيلي قدرتمنده ديگه نبايد همچين چيزايي توشديده بشه بدميگم !
بستگی داره "این چیزها" چی باشه و منظور از "قدرتمند" چی باشه. وقتی شما (یا هر کی که ازش پرسیدید) اطلاعی درباره نحوه کارکرد Indy ندارید، دلفی براتون چی کار کنه؟! Help اش رو بهتون داده، Demo رو بهتون داده، سورس رو بهتون داده، حالا شما بلد نیستید باهاش کار کنید، ایراد از شما هست، یا از ابزاری که استفاده می کنید؟!
قرار نیست هر جا که به بن بست رسیدید، یک خط توضیح بنویسید که بهتون گفته بودند دلفی قوی هست، ولی شما عکس را متوجه شدید. اگر مشکل شما با دلفی سر همچین چیزهایی هست که اشکالش بیشتر به خودتون بر می گرده، کسی اصرار نکرده از این ابزار استفاده کنید. یا سعی کنید درس اونو یاد بگیرید و استفاده کنید، یا قید استفاده از اون رو بزنید و از ابزار دیگه ایی استفاده کنید.

merced
جمعه 20 اردیبهشت 1387, 00:17 صبح
شما (baby tanha) بهتره از کامپوننت های ServerSocket و ClientSoket که با اضافه کردن بسته dclSokets.bpl در تب Internet دیده میشن استفاده کنی.

فکر کنم مشابه کامپوننت های VB باشه
ایندی با اون چیزی که تو ذهنته فرق داره. این برات راحت تره.
این قسمت اصلی کد استفاده از این دو کامپوننت :





var
Data: TMemoryStream
MyBuff: Array[0..65000] of Byte;
i: Integer;
Begin
Data := TMemory Stream.create ;
data.loadfrom ....

Data.Position := 0;
Data.Read(MyBuff, Data.Size);
ServerSocket1.Socket.Connections[n].SendBuf(MyBuff, Data.Size);




procedure TfMain.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
var
MyStream: TMemoryStream;
MyBuff: Array[0..4095] of byte;
b: Integer;
s : Byte ;
begin
b := Socket.ReceiveBuf(MyBuff, SizeOf(MyBuff));
MyStream := TMemoryStream.Create;
try
MyStream.Write(MyBuff, b);
finally
MyStream.Free;
end;
end;

baby_tanhaa
شنبه 21 اردیبهشت 1387, 17:00 عصر
شما (baby tanha) بهتره از کامپوننت های ServerSocket و ClientSoket که با اضافه کردن بسته dclSokets.bpl در تب Internet دیده میشن استفاده کنی.

فکر کنم مشابه کامپوننت های VB باشه
ایندی با اون چیزی که تو ذهنته فرق داره. این برات راحت تره.



با تشكر فراوان:بوس:
ميگم با اين كامپوننت كه شما معرفي كرديد نميشه استرينگ ارسال كرد؟؟

merced
یک شنبه 22 اردیبهشت 1387, 21:46 عصر
ServerSocket1.Socket.SendText(STR)

merced
یک شنبه 22 اردیبهشت 1387, 21:48 عصر
براي دريافت از در كلاينت در رويداد SocketClient1.Onread


s := Socket.ReceiveText

Mask
چهارشنبه 21 فروردین 1392, 14:14 عصر
سلام دوستان. کسی راه حلی برای این ضعف کامپوننت INdy TCPClient سراغ نداره؟
البته الان سویچ کردم رو سوکت اما برام خیلی سنگینه که همچین مشکلی تو این مجموعه عظیم وجود داره.
دوستان حرفه ای کمک.

یوسف زالی
چهارشنبه 21 فروردین 1392, 22:44 عصر
برای دونستن نحوه ی اضافه کردن رویداد OnExecute به این کامپوننت باید ببینید اون یکی کامپوننت چکار کرده.
با هم یک کمیش رو بریم جلو.

1- یک عدد TIdTCPServer رو فرم می ذاریم و روش Ctrl Click می کنیم
2- در کلاس تعریف شده می ایستیم تا ببینیم از چی مشتق شده. در اینجا از TIdComponent (هر چی می نویسم تو دلفی 7 دارم می گم)
3- یک عدد TIdTCPClient روی فرم می ذاریم و کنترل کلیک
4- در کلاس مربوطه می ایستیم و می بینیم که از TIdTCPConnection مشتق شده. روی TIdTCPConnection کنترل کلیک کرده می بینیم از TIdComponent مشتق شده.
5- با توجه به اشتراک در Hierarchy tree هر دو کامپوننت هر جی تو TIdComponent هست در هر دو هست. بنا بر این یک جایی در همون کلاس TIdTCPServer رویداد اضافه شده.
6- OnExecute رو در کلاس TIdTCPServer سرچ می کنیم. فقط یک جا کال می شه و اون هم در DoExecute هست.

نکته:
متد هایی مثل DoExecute معمولا پشت سر اکثر Property هایی از جنس Event وجود دارند و همگی هم Virtual هستند تا در مواقع اشتقاق کلاس بتونیم اونها و نحوه ی فراخوانی رویداد هاشون رو دستمون بگیریم و طبق سلیقه و نیازمون تغییرش (Override) بدیم.

حالا معلوم شد که تریگر کننده ی OnExecute همین DoExecute هست. می گردیم تو کد به دنبالش. در نسخه ی من اینجا یک بار کال می شه:


procedure TIdPeerThread.Run;

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

ببینیم کجای کلاس از این شی ها داریم.


constructor TIdTCPServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FBindings := TIdSocketHandles.Create(Self);
// Before Command handlers
FReplyTexts := TIdRFCReplies.Create(Self);
FCommandHandlers := TIdCommandHandlers.Create(Self);
FCommandHandlersEnabled := IdCommandHandlersEnabledDefault;
FGreeting := TIdRFCReply.Create(nil);
FMaxConnectionReply := TIdRFCReply.Create(nil);
FThreads := TThreadList.Create;
{----------------------------------------HERE---------------------------------------}
FThreadClass := TIdPeerThread;
{----------------------------------------HERE---------------------------------------}
FReplyUnknownCommand := TIdRFCReply.Create(nil);
//
FTerminateWaitTime := 5000;
FListenQueue := IdListenQueueDefault;
//TODO: When reestablished, use a sleeping thread instead
// fSessionTimer := TTimer.Create(self);
end;

به نظرم باقی ماجرا واضح باشه.


ThreadMgr.ThreadClass := ThreadClass;



property ThreadMgr: TIdThreadMgr read GetThreadMgr write SetThreadMgr;

ست و گت اون رو هم باید ببینیم.
ان شا ا... وقت شد در خصوص نوشتن کامپوننت یک فایل تصویری درست می کنم.
موفق باشید.

vcldeveloper
پنج شنبه 22 فروردین 1392, 22:37 عصر
کسی راه حلی برای این ضعف کامپوننت INdy TCPClient سراغ نداره؟
این ضعف کامپوننت نیست. اسم کامپوننت کارش را مشخص میکنه؛ IdTCPClient. یعنی این کامپوننت فقط درخواست ارسال میکنه و جواب درخواستش رو تحویل میگیره. ارسال و دریافت پیام هم در معماری Indy به صورت Synchronous هست، پس کلاینت یک درخواست ارسال میکنه، منتظر جواب میشه، جواب ارسالی از سرور رو دریافت میکنه. اگر کلاینت بدون اینکه خودش درخواستی ارسال کرده باشه، منتظر ارسال داده باشه، دیگه کارکرد کلاینتی نداره، بلکه میشه سروری که دیگران بهش وصل میشند!

بررسی اینکه چی باعث شده IdTCPServer متد OnExecute داشته باشه مشکلی از شما دوا نمیکنه. اون کلاس Threading به خاطر اینه که سرور می بایست برای هر اتصالی که از طرف کلاینت ها برقرار میشه، یک Thread ایجاد کنه، و به درخواست کلاینت در اون Thread پاسخ بده. حالا بر فرض هم که شما همچین چیزی رو به کلاینت اضافه کنید، اون دیگه اسمش کلاینت نیست.

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

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

Mask
شنبه 24 فروردین 1392, 16:05 عصر
در مورد :

این ضعف کامپوننت نیست. اسم کامپوننت کارش را مشخص میکنه؛ IdTCPClient. یعنی این کامپوننت فقط درخواست ارسال میکنه و جواب درخواستش رو تحویل میگیره
به نظر من دقیقا این ضعفه.
برای روشن تر شدن این موضوع یه بار دیگه به طور مفصل تر توضیح میدم:
ببینید : برنامه ای نوشتیم در سمت کلاینت و سرور ، در این برنامه قراره کلاینت مورد نظر به سرور وصل بشه .خوب یه TcpClient سمت کلاینت و یه TcpServer سمت سرور گزاشتیم.
مثلا پورت 1010 رو هم روی server اکتیو کردیم.
حالا برنامه کلاینت یه پیغام از روی اینترنت میده به سرور . آی پی سرور ولیده و پیغام رو میگیره.من هنوز سمت کلاینت Dis نشدمو هنوز کانکشن بازه .(اینم مد نظر داشته باشیم که کلاینت پشته NAt تشریف داره).خوب
حالا سرور روی پورت 1010 یه پیغامی مثلا 'ali' رو میگیره . توی TCPServerExecute گفتم که اگه پیام 'ali' دستت رسید ، تو روی همون کانکشنی که بازه یه پیغام 'reza' برگردون.
خوب با کد زیر این کار رو میکنم

AContext.Connection.IOHandler.WriteLn();
ایندفعه سمت کلاینت مجبورم که کار مسخره بکنم . تو یه تایمر هی دستور :

IdTCPClient1.IOHandler.ReadLn()
رو باید اجرا کنم تا بتونه روی خط رو بخونه . کاریم به قفل شدن برنامه ندارم . اصلا میگیم با یه حلقه تو یه ترد دیگه عملیات read رو انجام میدیم.
اما صالا این چه کاریه. کاملا غیر منطقی و غیر اصولی. چرا طراحان ایندی نیومدند یه ایونت به نام OnRead یا OnExecute برای TCPClient بسازن ، تا تو شرایطی که مجبوریم از این کامپوننت هم عملیات Read و Write رو انجام بدیم به مشکل نخوریم.
البته تو کامپوننت Socket یه همچین ایونتی هست . اما من موندم چرا ایندی نداره. بماند که سوکت دنگو فنگهای خودش رو هم داره.

MohsenB
سه شنبه 17 اردیبهشت 1392, 01:21 صبح
با سلام

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

1. اگر میخواید کارتون خیلی راحت بشه استفاده از ICS (http://www.overbyte.be/eng/products/ics.html)هم بد نیست .

2. خودتون کامپوننت IdTcpClient رو خصوصی سازی کنید . برای نمونه یک تکه کدش میونه اینجوری باشه :

TMBTCPDataAvailable = procedure (Sender :TObject; Data :string) of object;
//
TReadingThread = class(TThread)
protected
FConn: TMBIdTCPClient;
procedure Execute; override;
public
constructor Create(AConn: TMBIdTCPClient); reintroduce;
end;
//
TMBIdTCPClient = class(TIdTCPClient)
private
FReadThread : TReadingThread;
FOnConnected : TNotifyEvent;
FOnConnecting : TNotifyEvent;
FDisConnected : TNotifyEvent;
FOnReciveData : TMBTCPDataAvailable;
FOnDisConnected : TNotifyEvent;
...
published
property OnConnected: TNotifyEvent read FOnConnected write FOnConnected;
property OnConnecting :TNotifyEvent read FOnConnecting write FOnConnecting;
property OnDisConnected: TNotifyEvent read FOnDisConnected write FOnDisConnected;
property OnRecivedData :TMBTCPDataAvailable read FOnReciveData write FOnReciveData;
...
end;


///////////////////////////////
{ TReadingThread }

constructor TReadingThread.Create(AConn: TMBIdTCPClient);
begin
FConn := AConn;
inherited Create(False);
end;

procedure TReadingThread.Execute;
var Data :sting;
Len :Integer;
begin
while not Terminated and FConn.Connected do
begin
if FConn.IOHandler.InputBufferIsEmpty then
FConn.IOHandler.CheckForDataOnSource(0);
if not FConn.IOHandler.InputBufferIsEmpty then begin
Data:= FConn.IOHandler.ReadLn();
Synchronize(procedure begin FConn.OnRecivedData(FConn, Data) end);
end;
Sleep(10);
end;
end;

{ TMBIdTCPClient }

procedure TMBIdTCPClient.DoOnConnected;
begin
inherited;
FReadThread:= TReadingThread.Create(Self);
//
if Assigned(FOnConnected) then begin
FOnConnected(Self);
end;
end;

procedure TMBIdTCPClient.DoOnDisconnected;
begin
inherited;
if FReadThread <> nil then begin
FReadThread.Terminate;
end;
//
if Assigned(FOnDisConnected) then begin
FOnDisConnected(Self);
end;
end;

البته این کد رو امتحان نکردم چون مجبور شدم تغییراتی توش بدم تا ساده تر باشه .

موفق باشید

ahmad224051
چهارشنبه 25 اردیبهشت 1392, 19:56 عصر
با سلام
میتونید این کار را بکنید

client
procedure TForm1.Button1Click(Sender: TObject);
begin
With IdTCPClient1 do
begin
Host := '89.214.28.122';
Port := 1010;
if not Connected then
Connect;
IOHandler.Write(Byte($02));
IOHandler.Write('ali');
IOHandler.Write(Byte($03));
IOHandler.ReadByte; // skip $02
Memo1.Lines.Append( IOHandler.ReadLn(#03));
Disconnect;
end;
end;

server

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var s:string;
begin
AContext.Connection.IOHandler.ReadByte; // skip $02
s:= AContext.Connection.IOHandler.ReadLn(#03);
if s='ali' then
begin
AContext.Connection.IOHandler.Write(Byte($02));
AContext.Connection.IOHandler.Write('reza');
AContext.Connection.IOHandler.Write(Byte($03));
end;
end;

ahmad224051
پنج شنبه 26 اردیبهشت 1392, 20:27 عصر
جه ربطی داشت عامو
سوالو یه چند بار بخون شما...

این در جواب پست 2 بود