![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
||||
|
||||
|
Собственно вот в чём заморочка.
Создал проэкт программы, в которой не используются формы (тобишь без оконное приложение) и удалил Form из Uses. Далее объявил класс потока в юните таким образом. Код:
unit ServerTCP;
interface
Uses Classes, Sockets, Dialogs;
Type
TCPServerTCP = Class(TThread)
Protected
Procedure Execute; Override;
Private
Public
End;
type
IPData = packed record
LocalDomainName: WideString;
LocalHostAddr: WideString;
LocalHostName: WideString;
LocalHost: WideString;
LocalPort: WideString;
BytesReceived: Integer;
BytesSent: Integer;
end;
implementation
{ TCPServerTCP }
procedure TCPServerTCP.Execute;
var
IP: TIPSocket;
IPInfo: IPData;
begin
ShowMessage('Thread is work');
Try
IP := TIPSocket.Create(nil);
IPInfo.LocalHost := IP.LocalHost;
IPInfo.LocalPort := IP.LocalPort;
Finally
IP.Free;
End;
while Not Terminated do
Begin
End;
end;
end.В основной программе подключил юнит. Объявил переменную. Код:
Uses ServerTCP in 'ServerTCP.pas';{Все подключаемые модули приводить не стану.}
var
Server: TThread;
Далее создаю поток в программе. Код:
if (Server = Nil) then
Begin
Server := TCPServerTCP.Create(False){Не важно что здесь стоит, True с последующим Server.Resume; ли только False};
DataSend := 'Server to started.';
for I := 1 to LenGth(DataSend) do Data[i-1] := Byte(MidStr(DataSend,i,1)[1]);
SendToIP(Data, LenGth(DataSend),string(inet_ntoa(from.sin_addr)));
End;Дык вот, так же не имеет значения сколько основная программа будет работать, сообщение 'Thread is work' не появится до тех пор, пока не вызову завершение потока вот так. Код:
If Not (Server = Nil) then
Begin
Server.Terminate;
Server.Free;
DataSend := 'Server to stopped.';
for I := 1 to LenGth(DataSend) do Data[i-1] := Byte(MidStr(DataSend,i,1)[1]);
SendToIP(Data, LenGth(DataSend),string(inet_ntoa(from.sin_addr)));
End;В чём беда ? Читал где то что вот якобы поток выполняется определённый системой квант времени. Но как этот квант ему дать ? Ни кто не работал с потоками в программе без использования TForm ? Последний раз редактировалось seeman_tm, 08.02.2013 в 03:23. |
|
#2
|
||||
|
||||
|
Бряк на begin в execute поставь и посмотри, попадает туда или нет.
Так-то вроде не видно ошибок . |
|
#3
|
||||
|
||||
|
Цитата:
Не могу догнать, на какой бегин и чё поставить ? Вообще то прога работает, она у меня принимает юдп пакеты, делает определённые действия и отправляет ответ о ходе выполненных действиях, в частности то что "поток будущего TCP сервера создан", "его айпи такой то", "поток будущего TCP сервера завершен" и так же откликается на завершение вообще всей программы. Загвоздка в другом, процедура Execute у потока не выводит сообщение о том что он работает после его создания, пока не сделаешь вызов Server.Terminate. Что самое интересное, так это то, что если в код программы поставить {$APPTYPE CONSOLE} то и поток начинает работать сразу после его создания, только вот чёрное окно MSDos'a ни к чему. Могу выложить полный код программы и модуля если надо, секрета тут нет. Последний раз редактировалось seeman_tm, 08.02.2013 в 08:59. |
|
#4
|
||||
|
||||
|
Код:
procedure TCPServerTCP.Execute;
var
IP: TIPSocket;
IPInfo: IPData;
begin <<< вот сюда точку останова (клавиша F5), запустись по F9 и подожди, когда сюда отладчик прыгнет
ShowMessage('Thread is work'); |
|
#5
|
||||
|
||||
|
не надо не в VCL приложении использовать TThread и VCL диалоги.
Код:
program Project1; uses Windows, Messages; function ThreadProc(Thread: Pointer): Integer; begin Result:=0; Windows.Beep(1000, 100); MessageBox(0, 'MessageBox', 'ThreadProc', MB_OK); EndThread(0); end; var FHandle: THandle; FThreadID: THandle; begin FHandle := BeginThread(nil, 0, @ThreadProc, nil, 0, FThreadID); WaitForSingleObject(FHandle, INFINITE); CloseHandle(FHandle); end. |
|
#6
|
||||
|
||||
|
NumLock, поменял ShowMessage на MessageBox в юните unit ServerTCP;
и всё заработало как было задумано. Можешь объяснить такую штуку ? Почему Цитата:
|
|
#7
|
||||
|
||||
|
он связан с Application. его синхронизация к примеру.
|
|
#8
|
||||
|
||||
|
Так мне синхронизация ни к чему.
Этот поток не будет ни коим образом, кроме создания и завершения, взаимодействовать с основной программой. Так же не будет в будущем выводить ни какие сообщения. Цель потока, создание компонента TCPServer, обслуживание запросов подключенного пользователя. Проще сказать, это будет подобие прокси сервера, через который будет осуществляться запрос и подключение интернет страниц. Вот как я это вижу. 1. При запуске программы создаётся UDP сокет. Который при получение на свой порт определённого сообщения создаёт или завершает поток TCP Сервера, отвечает на запрос айпи сервера, а так же завершает программу совсем по запросу клиента. Так же через UDP оправляется ответ о выполненном действии. {Первый пункт выполнен}. 2. При создании потока TCP Сервера, поток создаёт компонент TCPServer и начинает ожидать подключения TCP клиента. После подключения клиента читает поля HTTP пакета полученного от клиента, в частности поле Host, создаёт поток другого TCP клиента и передаёт в него полученный от клиента пакет со значением Host. Ожидает получения данных от созданного потока TCP клиента. 3. Созданный поток TCP клиента в свою очередь, Подключается к серверу указанному в Host, переотправляет полученный пакет. Собирает все пакеты которыми ответил HTTP сервер и возвращает их TCP серверу. 4. После получения данных от потока TCP клиента, поток TCP Сервера переотправляет их уже подключенному к нему клиенту. Советы по реализации какие нибудь будут ? Последний раз редактировалось seeman_tm, 08.02.2013 в 17:46. |
|
#9
|
||||
|
||||
|
Возник вопрос по Accept модуля WinSock.
Проблема в том, что функция Код:
sClient := Accept(sServerListen, @ClientAddr, @iSize); Останавливает выполнение потока на себе до тех пор, пока какой нить клиент не подключится к серверу. Как можно ограничить по времени выполнение вышеуказанной функции ? Вот код потока ожидающего подключения клиентов. Код:
Procedure TServerThread.Execute;
Var
wData: WSADATA;
sServerListen, sClient: TSOCKET;
LocalAddr, ClientAddr: SockAddr_in;
iSize: Integer;
sl: TCPClientThread;
Begin
// Загрузка WinSock
if WSAStartup(MAKEWORD(1,1), wData) <> 0 then
Begin
MessageBox(0,'Не удалось загрузить WinSock.','Ошибка.',0);
Exit;
End;
// Создание сокета
sServerListen := Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if sServerListen = INVALID_SOCKET then
Begin
MessageBox(0,'Ошибка создания сокета.','Ошибка.',0);
Exit;
end;
// Заполнение структуры адреса
LocalAddr.sin_addr.S_addr := HTONL(INADDR_ANY);
LocalAddr.sin_family := AF_INET;
LocalAddr.sin_port := HTONS(2990);
// Связывание сокета с локальным адресом
if bind(sServerListen, LocalAddr, SizeOf(LocalAddr)) = SOCKET_ERROR then
Begin
TestWinSockError('Bind');
Exit;
End;
// Прослушивание
if TestFuncError(Listen(sServerListen,4), 'Listen') then Exit;
while not Terminated do
Begin
iSize := SizeOf(ClientAddr);
// Приём нового соединения
sClient := Accept(sServerListen, @ClientAddr, @iSize);
if sClient = INVALID_SOCKET then
Begin
TestWinSockError('accept');
Break;
end
Else
Begin
// Соединение принято, создаём поток
sl := TCPClientThread.Create(True);
sl.Sock := sClient;
sl.Resume;
End;
End;
sl.Terminate;
sl.WaitFor;
FreeAndNil(sl);
CloseSocket(sServerListen);
end; |
|
#10
|
||||
|
||||
|
Немного не в тему, но можно вытащить ф-ю в отдельный поток, пусть его тормозит.
Последний раз редактировалось M.A.D.M.A.N., 11.02.2013 в 07:53. |
|
#11
|
||||
|
||||
|
Цитата:
|
|
#12
|
||||
|
||||
|
Цитата:
Всё бы ничего, но вот у моего сервера нет Handle, он у меня как процесс в винде сидит, без всяких визуалок. Поэтому Неблокирующий режим не подходит. |
|
#13
|
||||
|
||||
|
Эм. А где связь? Неблокирующий режим назначается сокету. Я сам делал неблокирующие сервера без визуалок. ioctlsocket, select. И все дела.
|
|
#14
|
||||
|
||||
|
Цитата:
Ха, гениально. Вот тока это не поможет. Сам то работал с WinSock ? Если сделать вход в функцию, то из неё только два выхода, 1. Подключился клиент. 2. Вывалилась ошибка. Поток завершай не завершай, если ошибок нет, то он всё равно будет работать пока кто нить не подключится. После вызова Terminate, поток пашет до тех пор пока не подключится клиент, после чего поток сразу завершается, но ни как не раньше. |
|
#15
|
||||
|
||||
|
Вот обработчик сообщений в проге.
Код:
procedure TServerThread.WM_NetMsg(var M: TMessage);
Var
ClientSocket: TSOCKET;
iRet: Integer;
sRecvBuff: Array [0..1023] Of Byte;
sSendString, CH: String;
I: Integer;
begin
case M.LParam Of
// Прибыл запрос на соединение
FD_ACCEPT:
Begin
MessageBox(0,'Ошибка получения данных.','Внимание !!!',0);
ClientSocket := Accept(M.WParam,nil, nil);
WSAAsyncSelect(ClientSocket, Handle, WM_USER+1,
FD_READ {or FD_WRITE} or FD_CLOSE);
End;
// Прибыли данные
FD_READ:
Begin
iRet := recv(M.WParam, sRecvBuff,SizeOf(sRecvBuff),0);
if (iRet = SOCKET_ERROR) then
Begin
MessageBox(0,'Ошибка получения данных.','Внимание !!!',0);
Exit;
End;
for i := 0 to iRet-1 do sSendString := sSendString + chr(sRecvBuff[i]);
if sSendString[LenGth(sSendString)] = chr($10) then
sSendString:= Copy(sSendString,1,LenGth(sSendString)-2);
if sSendString <> 'get' then Exit;
sSendString := 'Command Get - OK';
for I := 1 to LenGth(sSendString) do
Begin
CH := sSendString[i];
sREcvBuff[i-1] := Byte(CH[1]);
End;
iRet := send(M.WParam, sRecvBuff, LenGth(sSendString),0);
if (iRet = SOCKET_ERROR) then
Begin
MessageBox(0,'Ошибка передачи данных.','Внимание !!!',0);
Exit;
End;
End;
// Сокет закрыт
FD_CLOSE:
Begin
CloseSocket(M.WParam);
End;
end;
end;Цитата:
Приведи пример как делал. Потому что я нашел только такое использование. Там сама винда, якобы, через Message, начинает слать в прогу события произошедшие на сокете. Последний раз редактировалось seeman_tm, 11.02.2013 в 21:50. |