Форум: "Сети";
Текущий архив: 2004.02.02;
Скачать: [xml.tar.bz2];
ВнизКак реализовать чтоб сервре и клиент слушали порт? Найти похожие ветки
← →
h0use (2003-11-25 17:14) [0]Есть сервак, у которого в методе OnExecute
procedure TFM.TCPServerExecute(AThread: TIdPeerThread);
var
AMsg : TCommBlock;
Msg : String;
begin
if not AThread.Terminated and AThread.Connection.Connected then
try
Msg:=AThread.Connection.ReadLn;
if Msg="" then exit;
AThread.Connection.ReadBuffer(AMsg,SizeOf(AMsg));
ShowMessage(IntToStr(AMsg.Command)+IntToStr(AMsg.Argument1)+IntToStr(AMsg.Argument2)+AMsg.Msg);
case AMsg.Command of //
cmdLogin : ServerLogin(AMsg,AThread);
cmdLogout : ServerLogout(AMsg,AThread);
cmdCommand: ServerCommand(AMsg,AThread);
cmdSQL : ServerSQL(AMsg,AThread);
cmdMessage: ServerChat(AMsg,AThread);
end; // case
except
on E: Exception do
SaveLog(0,3,"Socket read error: " + e.Message);
end;
end; // TCPServerExecute
Работает и сам сервак не виснет, но в клиенте в процедуре
procedure TfmMain.TimerTimer(Sender: TObject);
var
AMsg: TCommBlock;
Msg : String;
begin
if (not TCPClient.Connected) then exit;
try
Msg:=TCPClient.ReadLn(#10,50); <------------- Вот здесь висим после первого обмена информацией
if Msg="<<<" then
begin
TCPClient.ReadBuffer(AMsg,SizeOf(AMsg));
case AMsg.Command of //
cmdLogin : ClientConnect(AMsg);
cmdLogout: ClientDisconnect(AMsg);
end; // case
end;
except
on e: Exception do
ShowMessage(e.Message);
end; // try/except
Application.ProcessMessages;
end;
Как сделать так, чтоб клиент при ожидании какой-либо инфы от сервера не вис?
← →
Digitman (2003-11-25 17:20) [1]из кода совершенно непонятно, кто из них, в соответствии с твоим протоколом инф.обмена, первый должен "говорить", а кто "слушать"
оба сразу "слушают" и ждут неизвестно чего
← →
h0use (2003-11-25 17:22) [2]А как сделать так чтоб клиент не вис, пока сервер думает что ему(клиенту) отправить?
← →
Digitman (2003-11-25 17:33) [3]а где утебя сервер что-то "думает", а потом "отправляет" ?
я вот вижу, что первым делом сервер ждет чего-то от клиента
Msg:=AThread.Connection.ReadLn;
а клиент в это же время ждет чего-то от сервера
Msg:=TCPClient.ReadLn(#10,50)
)))
и тишина гробовая стоит поэтому)
← →
h0use (2003-11-25 17:36) [4]У меня сервер реагирует на сообщения от клиента и в соотв. процедурах ему отправляет что-то. Например нужно сделать как чат, как только один пользователь послал мессагу, сервре ее перенаправил другому пользователю, поэтому у меня и сервер слушает и клиент.
← →
h0use (2003-11-25 17:52) [5]Неужели это нереальная задача для Инди?
← →
Digitman (2003-11-25 18:17) [6]
> У меня сервер реагирует на сообщения от клиента
а где в твоем коде клиент ХОТЬ ЧТО-ЛИБО посылает серверу ?!
> Неужели это нереальная задача для Инди?
при чем здесь инди ? Совершенно ни при чем ! Это лишь - одна из оболочек транспортного механизма, не более того
← →
h0use (2003-11-26 09:40) [7]Клиент серверу отсылает сообщения в ответ на сообщения от сервера и наоборот. Но в промежутке когда и сревре и клиент ничего не делают, сообщений нет, можно конечно чтоб они занимались "пинг-понгом", но неужели нельзя сделать так чтоб при простое клиент мог работать, при этом в любой момент ожидать сообщение от сервера.
← →
Reindeer Moss Eater (2003-11-26 09:44) [8]Какой смысл ты вкладываешь в термины "клиент не работает" "клиент мог работать"?
Он у тебя что, аварийно завершает свой процесс и выгружается из памяти?
← →
Digitman (2003-11-26 09:48) [9]
> неужели нельзя сделать так чтоб при простое клиент мог работать,
> при этом в любой момент ожидать сообщение от сервера.
в кл.приложении организуй доп.код.поток
пусть в нем происходит коннект к серверу и ожидание сообщений от него
в тоже время осн.код.поток параллельно может заниматься всем чем угодно
← →
Digitman (2003-11-26 09:50) [10]
> Reindeer Moss Eater
клиент у него "виснет" на первом же блокирующем ReadLn() в обработчике таймера (нахрена там таймер ? ума не приложу)
← →
Reindeer Moss Eater (2003-11-26 10:12) [11]Это "пунктик" такой есть.
Если надо что-то сделать несколько раз, то без таймера ну никак.
А уж если приложение консольное, и таймер некуда "кинуть", то вообще засада, задача для ктн, как минимум.
:)
← →
Reindeer Moss Eater (2003-11-26 10:18) [12]TidAntifreeze.
Занимается обработкой сообщений во время синхронных вызовов.
← →
h0use (2003-11-26 10:24) [13]А подробней?
← →
Reindeer Moss Eater (2003-11-26 10:36) [14]Ты уже попробовал изпользовать TidAntifreeze?
← →
h0use (2003-11-26 10:42) [15]Нет, я не нашел примера, а просто кидать его на форму не приводит к каим либо изменениям, потом вообще не понятно куда его кидать, на сервер или клиент, или обоим сразу
← →
Reindeer Moss Eater (2003-11-26 11:31) [16]"Кидать" его надо в GUI приложение.
Если синхронные методы библиотеки вызываются из главного потока приложения и если требуется обеспечить доступность UI во время работы.
Один экземпляр на все приложение.
Если свойство Active равно True, то пользовательский интерфейс не будет "засыпать" во время выполнения синхронных методов.
← →
h0use (2003-11-26 11:54) [17]Это я понял, но, у меня даже при установке флага OnlyWhenIdle в False все равно прикладуха виснет :(
← →
Reindeer Moss Eater (2003-11-26 12:10) [18]Код твоего клиента - одно сплошное недоразумение.
Таймер там что делает?
← →
h0use (2003-11-26 12:26) [19]Как что, с периодичностью в секунду опрашивает порт, если там сообщения...
← →
Reindeer Moss Eater (2003-11-26 12:29) [20]Замечательно.
Вызвали ReadLn первый раз.
Данных не пришло, возврата из метода пока нет,
тут срабатывает таймер, метод вызывается еще раз у того же самого экземпляра.
Данных не пришло, возврата из метода пока нет,
тут срабатывает таймер, метод вызывается еще раз у того же самого экземпляра.
Круто, правда?
← →
Digitman (2003-11-26 12:42) [21]
> Reindeer Moss Eater
> Данных не пришло, возврата из метода пока нет,
> тут срабатывает таймер, метод вызывается еще раз у того
> же самого экземпляра.
ты не загнул ли ?
imho, загнул явно
это ж все - осн.код.поток !
если сервер "молчит", то таймер "тикнет" всего один раз, и больше не дождется автор его "тиканий" - обработчик таймера-то "висит" на исполнении блокирующего ReadLn()...
← →
h0use (2003-11-26 12:43) [22]А как сделать ПРАВИЛЬНО?
← →
Digitman (2003-11-26 12:44) [23]
> Reindeer Moss Eater
а-а-а ... ну если ты подразумеваешь инди-антифриз, то - да, это засада, конечно
← →
Reindeer Moss Eater (2003-11-26 12:47) [24]ты не загнул ли ?
Сообщения-то все же обрабатываются благодаря антифризу.
← →
h0use (2003-11-26 12:48) [25]Что самое интерсное, что пример я взял из демки самой Инди, она у меня тоже виснет. Но самое интерсное, что когда я использую Антифриз все замечательно работает до момента когда я хочу форму двинуть мышкой или например максимизировать.
← →
Digitman (2003-11-26 12:48) [26]
> h0use
я ж тебе сказал уже : транспорт (т.е. логику обращений к TCPClient"у) выноси в отдельный кодовый поток, а обработку данных, полученных с пом.транспорта, выполняй в другом (например - основном) код.потоке
что непонятного ?
убирай свои таймеры ! начерта они здесь не нужны)
← →
h0use (2003-11-26 12:51) [27]Т.е. делать отдельный TThread где запускать TCPClienta, а данные sincronize с данными из форм?
← →
Digitman (2003-11-26 12:51) [28]
> Reindeer Moss Eater © (26.11.03 12:47) [24]
ну да, я уже вижу - ты эту ситуацию "замечательную" расписал именно в случае с антифризом
вообще-то дурь все это - все эти "антифризы", лучше не пользовать : нет прозрачности и наглядности собственной асинхр.логики
← →
Reindeer Moss Eater (2003-11-26 12:53) [29]Лучше убери таймер и не надо вторичного потока.
Иначе запутаешься с потоком еще глубже чем сейчас
← →
Digitman (2003-11-26 12:56) [30]
> h0use © (26.11.03 12:51) [27]
при чем здесь "форма" ? трансп.поток синхронизировать нужно не с "формой", а с потоком, который будет обрабатывать поступающие из трансп.потока данные и/или передавать трансп.потоку данные, предназначенные для передачи их партнеру по инф.обмену
← →
h0use (2003-11-26 12:56) [31]Хм, а как же тогда сервак слушать?
← →
h0use (2003-11-26 12:58) [32]
> при чем здесь "форма" ? трансп.поток синхронизировать нужно
> не с "формой", а с потоком, который будет обрабатывать поступающие
> из трансп.потока данные и/или передавать трансп.потоку данные,
> предназначенные для передачи их партнеру по инф.обмену
Все здорово, только нигде нет примера как на инди эти потоки реализовать, я сам так в начале хотел сделать, только не знаю каими методами можно разделить потоки на входящие и исходящие
← →
h0use (2003-11-26 13:01) [33]пока у меня так
procedure TfmMain.ClientLogin;
var
AMsg: TCommBlock;
begin
try
Application.CreateForm(TPasswordDlg, PasswordDlg);
PasswordDlg.ShowModal;
if PasswordDlg.ModalResult=mrOK then
try
BAConn:=TSrvConn.Create;
BAConn.Host:="h0usexp";
BAConn.Port:=1000;
BAConn.User:=PasswordDlg.edLogin.Text;
BAConn.Password:=PasswordDlg.edPassword.Text;
TCPClient.Host:=BAConn.Host;
TCPCLient.Port:=BAConn.Port;
LogEvent.Active:=True;
TCPClient.Connect(10000);
AMsg.Command:=cmdLogin;
AMsg.Argument1:=argLoginClient;
if (BAConn.User<>"") and (BAConn.Password<>"")
then AMsg.Argument2:=optLoginHasInfo
else AMsg.Argument2:=optLoginNoInfo;
AMsg.Msg:=BAConn.User+"|"+BAConn.Password;
while true do
if TCPClient.Connected then
begin
SendMsg(AMsg);
break;
end;
ledConnected.Color:=clLime;
isConnected:=TCPClient.Connected;
btnConn.Hint:="
← →
Digitman (2003-11-26 13:14) [34]убирай ты свой таймер, говорю тебе ! ни кселу ни к городу он здесь !
есть событие OnWork() , оно тебя известит о приходе некоторой порции данных от партнера, вот в его обработчике и считывай РЕАЛЬНО пришедшее от партнера кол-во байт данных
← →
Reindeer Moss Eater (2003-11-26 13:32) [35]Скелет. Частный пример. Не образец для подражания.
const WM_SERVER_MSG = WM_USER + 101;
type
TForm1 = class(TForm)
IdTCPClient1: TIdTCPClient;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
procedure SessionWithServer;
procedure OnServerMessage(var Msg : TMessage); message WM_SERVER_MSG;
public
{ Public declarations }
end;
implementation
{$R *.DFM}
type
PMyServerCmd = ^TMyServerCmd;
TMyServerCmd = record
sc_Cmd_Type : Word;
Param1,
Param2,
Param3 : string[30];
end;
var
SessionIsOver : boolean = False;
procedure TForm1.Button1Click(Sender: TObject);
begin
if ConnectClientToServerUsingIpAndPort("127.0.0.1",777) then
SessionWithServer;
end;
procedure TForm1.SessionWithServer;
var Cmd : TMyServerCmd;
begin
while not SessionIsOver do
try
IdTCPClient1.ReadBuffer(Cmd,SizeOf(Cmd));
SendMessage(Self.Handle,WM_SERVER_MSG,Integer(@Cmd),0);
except
Break;
end;
end;
procedure TForm1.OnServerMessage(var Msg: TMessage);
begin
case PMyServerCmd(Msg.WParam).sc_Cmd_Type of
1: begin
ShowMessage("Сервер требует сказать имя и пароль");
if ShowLoginDialog then
IdTCPClient1.WriteLn(UserName);
IdTCPClient1.WriteLn(Password);
end
3: ShowMessage("Делай то");
4: ShowMessage("Делай сё");
5: ShowMessage("Делай пятое");
6: ShowMessage("Делай десятое");
7: begin
ShowMessage("Нас отключают");
SessionIsOver:=True;
end;
end;
end;
← →
h0use (2003-11-26 13:40) [36]Спраибо, до сообщений я не догадался, буду пробовать
← →
Digitman (2003-11-26 13:43) [37]толку-то) ... теперь "висеть" будешь на строчке
IdTCPClient1.ReadBuffer(Cmd,SizeOf(Cmd))
← →
h0use (2003-11-26 13:46) [38]С Антифризом не должно
← →
Reindeer Moss Eater (2003-11-26 13:46) [39]Зато нам поверили, что таймер не нужен
← →
Digitman (2003-11-26 13:57) [40]
> Reindeer Moss Eater © (26.11.03 13:46) [39]
LOL
> h0use © (26.11.03 13:46) [38]
нафига ?! ну нафига тебе, скажи на милось, всякие таймеры да антифризы ? если есть событие OnWork(), АСИНХРОННО извещающее тебя о наступлении сетевого транспортного события а-ля "сервер ан сей момент прислал N байт, можно безо всяких задержек прочитать эти N байт из буфера и передать их на обработку куда-то" ?
Страницы: 1 2 вся ветка
Форум: "Сети";
Текущий архив: 2004.02.02;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.009 c