![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как реализовать чтоб сервре и клиент слушали порт? [D7, Win95/98, Win2k, WinXP]
h0use © (2003-11-25 17:14:00)
Есть сервак, у которого в методе 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;
Как сделать так, чтоб клиент при ожидании какой-либо инфы от сервера не вис?
h0use (2003-11-26 13:46:00) [21]
С Антифризом не должно
Digitman (2003-11-26 13:43:00) [22]
толку-то) ... теперь "висеть" будешь на строчке
IdTCPClient1.ReadBuffer(Cmd,SizeOf(Cmd))
h0use (2003-11-26 13:40:00) [23]
Спраибо, до сообщений я не догадался, буду пробовать
Reindeer Moss Eater (2003-11-26 13:32:00) [24]
Скелет. Частный пример. Не образец для подражания.
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;
Digitman (2003-11-26 13:14:00) [25]
убирай ты свой таймер, говорю тебе ! ни кселу ни к городу он здесь !
есть событие OnWork() , оно тебя известит о приходе некоторой порции данных от партнера, вот в его обработчике и считывай РЕАЛЬНО пришедшее от партнера кол-во байт данных
h0use (2003-11-26 13:01:00) [26]
пока у меня так
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:="
h0use (2003-11-26 12:58:00) [27]
> при чем здесь "форма" ? трансп.поток синхронизировать нужно
> не с "формой", а с потоком, который будет обрабатывать поступающие
> из трансп.потока данные и/или передавать трансп.потоку данные,
> предназначенные для передачи их партнеру по инф.обмену
Все здорово, только нигде нет примера как на инди эти потоки реализовать, я сам так в начале хотел сделать, только не знаю каими методами можно разделить потоки на входящие и исходящие
Digitman (2003-11-26 12:56:00) [28]
> h0use © (26.11.03 12:51) [27]
при чем здесь "форма" ? трансп.поток синхронизировать нужно не с "формой", а с потоком, который будет обрабатывать поступающие из трансп.потока данные и/или передавать трансп.потоку данные, предназначенные для передачи их партнеру по инф.обмену
h0use (2003-11-26 12:56:00) [29]
Хм, а как же тогда сервак слушать?
Reindeer Moss Eater (2003-11-26 12:53:00) [30]
Лучше убери таймер и не надо вторичного потока.
Иначе запутаешься с потоком еще глубже чем сейчас
Digitman (2003-11-26 12:51:00) [31]
> Reindeer Moss Eater © (26.11.03 12:47) [24]
ну да, я уже вижу - ты эту ситуацию "замечательную" расписал именно в случае с антифризом
вообще-то дурь все это - все эти "антифризы", лучше не пользовать : нет прозрачности и наглядности собственной асинхр.логики
h0use (2003-11-26 12:51:00) [32]
Т.е. делать отдельный TThread где запускать TCPClienta, а данные sincronize с данными из форм?
Digitman (2003-11-26 12:48:00) [33]
> h0use
я ж тебе сказал уже : транспорт(т.е. логику обращений к TCPClient"у) выноси в отдельный кодовый поток, а обработкуданных, полученных с пом.транспорта, выполняй в другом (например - основном) код.потоке
что непонятного ?
убирай свои таймеры ! начерта они здесь не нужны)
h0use (2003-11-26 12:48:00) [34]
Что самое интерсное, что пример я взял из демки самой Инди, она у меня тоже виснет. Но самое интерсное, что когда я использую Антифриз все замечательно работает до момента когда я хочу форму двинуть мышкой или например максимизировать.
Reindeer Moss Eater (2003-11-26 12:47:00) [35]
ты не загнул ли ?
Сообщения-то все же обрабатываются благодаря антифризу.
Digitman (2003-11-26 12:44:00) [36]
> Reindeer Moss Eater
а-а-а ... ну если ты подразумеваешь инди-антифриз, то - да, это засада, конечно
h0use (2003-11-26 12:43:00) [37]
А как сделать ПРАВИЛЬНО?
Digitman (2003-11-26 12:42:00) [38]
> Reindeer Moss Eater
> Данных не пришло, возврата из метода пока нет,
> тут срабатывает таймер, метод вызывается еще раз у того
> же самого экземпляра.
ты не загнул ли ?
imho, загнул явно
это ж все - осн.код.поток !
если сервер "молчит", то таймер "тикнет" всего один раз, и больше не дождется автор его "тиканий" - обработчик таймера-то "висит" на исполнении блокирующего ReadLn()...
Reindeer Moss Eater (2003-11-26 12:29:00) [39]
Замечательно.
Вызвали ReadLn первый раз.
Данных не пришло, возврата из метода пока нет,
тут срабатывает таймер, метод вызывается еще раз у того же самого экземпляра.
Данных не пришло, возврата из метода пока нет,
тут срабатывает таймер, метод вызывается еще раз у того же самого экземпляра.
Круто, правда?
h0use (2003-11-26 12:26:00) [40]
Как что, с периодичностью в секунду опрашивает порт, если там сообщения...