Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как реализовать чтоб сервре и клиент слушали порт? [D7, Win95/98, Win2k, WinXP]


Страницы:   1 2 3

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]

Как что, с периодичностью в секунду опрашивает порт, если там сообщения...


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо