![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как правильно написать socks-сервер? [D7, WinXP]
zsergey © (2008-01-13 21:01:00)Привет господа! Есть такая задача: написать простой сокетный сервер, который должен обслуживать несколько подключений одновременно. Я только начал разбирать с этим вопросом, просьба, не ругать. Вот навоял небольшой работающий пример, правда без обработок ошибок:
procedure TForm1.startserverClick(Sender: TObject);
var S,AcceptedSock:TSocket;
Addr:TSockAddr;
Data:TWSAData;
Len:Integer;
buf : array[0..30] of byte;
begin
WSAStartup($101,Data);
S:=Socket(AF_Inet,Sock_Stream,0);
Addr.sin_family:=PF_Inet;
Addr.sin_port:=HToNS(5005);
Addr.sin_addr.S_addr:=InAddr_Any;
FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0);
Bind(S,Addr,SizeOf(TSockAddr));
Listen(S,SoMaxConn);
Len:=SizeOf(TSockAddr);
AcceptedSock:=Accept(S,@Addr,@Len);
Recv(AcceptedSock,buf, sizeof(buf),0);
// дальше обрабатываю данные
end;
тут используется блокирующий сокет, который отрабатывает одно соединение. Подскажите пожалуйста, как здесь организовать обслуживание несколько подключений, в какую сторону хотя бы смотреть...
ketmar (2008-01-15 09:13:00) [41]>[6] zSergey (14.01.08 16:31)
>какой должен быть механизм обмена между 2 приложениями
рабочий он должен быть. далее конкретизируется под конкретную задачу.
вот с той же адынцэ — это тебе ActiveX писать. где, кстати, пофигу, компоненты али не компоненты — всё равно будет жирное (если ты, конечно, не хардкорщик, желающий ваять ActiveX «с нуля»).
Сергей М. (2008-01-15 08:21:00) [42]
> о каких компонентах речь идет?
Мало ли таковых существует !
TTCPServer, TServerSocket у тебя прямо под рукой имеются.
> как запихнуть компонент в Dll
Точно также как в exe
DVM (2008-01-14 22:59:00) [43]
> теперь задача немного усложняется: сам сервер я написал
> в виде библиотеки (*.dll), увы такое требование. Сервер
> будет запускаться сторонним приложением. Здесь проблем нет.
> Вопрос в том, как сервер должен передавать данные в вызвавшую
> его программу?.
А разве сервер запущенный из dll некой сторонней программой не находится в адресном пространстве процесса этой программы? Это передача не между процессами, а между частями одного и того же приложения (в данном случае между потоками).
Самый простой и надежный способ передачи через сообщения Windows.
zSergey (2008-01-14 16:40:00) [44]
> Тебе что, компонентов готовых мало ?)
Кстати, а о каких компонентах речь идет?
zSergey (2008-01-14 16:31:00) [45]> Сергей М.
ну зачем жет так резко, уважаемый? Ничего плохо в том, что я хочу разобрать с WinsockAPI нет. Да и сама библиотечка будет намного легче весить без компонент. Кстати, а как запихнуть компонент в Dll ? :)Да и вопрос ведь в том, какой должен быть механизм обмена между 2 приложениями, пусть даже с использованием компонент?
Сергей М. (2008-01-14 16:16:00) [46]
> zSergey (14.01.08 15:35) [4]
Какого хрена ты вообще взялся за WinsockAPI ?
Тебе что, компонентов готовых мало ?)
zSergey (2008-01-14 15:35:00) [47]теперь задача немного усложняется: сам сервер я написал в виде библиотеки (*.dll), увы такое требование. Сервер будет запускаться сторонним приложением. Здесь проблем нет. Вопрос в том, как сервер должен передавать данные в вызвавшую его программу?. Поясняю задачу: сам сервер пишется для связки с 1с v.8. Т.к. у 1с нет стандартных средств для работы с сокетами, приходиться прибегнуть с помошью внешних компонент (dll), где собственно будет находится сам функционал сервера. Далее, приняв данные, сервер должен в реальном времени передать их приложению-хозяину, приложение в это время не находиться в режиме ожидания, а продолжает выполнять весь свой функционал. Я понимаю, что это форум отношения к 1с не имеет, потому я пока рассматриваю вариант взаимодействия программы и сервера на delphi. Буду благодарен любым идеям.
zsergey (2008-01-13 21:25:00) [48]Cпасибо за пример, буду разбираться.
DVM (2008-01-13 21:08:00) [49]Вот как то так (в коде могут быть ошибки!):
program server;
{$APPTYPE CONSOLE}
uses
SysUtils,
Winsock,
Windows;
type
ThreadData = record
Socket: TSocket;
end;
PThreadData = ^ThreadData;
var
WSAData: TWSAData;
ListenSocket, ClientSocket: TSocket;
Info: PThreadData;
SockAddr: TSockAddr;
ThreadId: THandle;
hClientThread: Thandle;
const
Port = word(25);
//------------------------------------------------------------------------------
procedure SocketThread(Info: PThreadData);
var
SockName: TSockAddr;
NameLen, OptLen: Integer;
Buf: PChar;
RecvSize: integer;
s: TSocket;
BuffSize: integer;
begin
s := Info^.Socket;
try
NameLen := SizeOf(TSockAddr);
if GetPeerName(s, SockName, NameLen) <> 0 then exit;
Writeln(format('Client accepted, remote address [%s].', [inet_ntoa(SockName.sin_addr)]));
OptLen := SizeOf(BuffSize);
if GetSockOpt(s, SOL_SOCKET, SO_RCVBUF, pointer(@BuffSize), OptLen) <> 0 then exit;
writeln(format('Receive buffer size [%d]', [BuffSize]));
GetMem(Buf, BuffSize);
try
repeat
RecvSize := recv(s, Buf^, BuffSize, 0);
sleep(5);
if RecvSize > 0 then
writeln(format('Received from client: %s', [strpas(Buf)]));
until RecvSize <= 0;
finally
FreeMem(Buf, BuffSize);
end;
Writeln(format('Client disconnected, remote address [%s].',[inet_ntoa(SockName.sin_addr)]));
finally
CloseSocket(s);
Dispose(Info);
end;
end;
//------------------------------------------------------------------------------
begin
Writeln('WSA Initialize...');
if WSAStartup($101, WSAData) <> 0 then exit;
try
Writeln(format('Creating socket on port [%d].', [Port]));
ListenSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if ListenSocket = INVALID_SOCKET then exit;
try
FillChar(SockAddr, SizeOf(TSockAddr), 0);
SockAddr.sin_family := AF_INET;
SockAddr.sin_port := htons(Port);
SockAddr.sin_addr.S_addr := INADDR_ANY;
Writeln('Binding socket...');
if Bind(ListenSocket, SockAddr, SizeOf(TSockAddr)) <> 0 then exit;
if listen(ListenSocket, SOMAXCONN) <> 0 then exit;
Writeln('Socket status: listening...');
repeat
Writeln('wait');
ClientSocket := accept(ListenSocket, nil, nil);
if ClientSocket <> INVALID_SOCKET then
begin
New(Info);
Info^.Socket := ClientSocket;
hClientThread := BeginThread(nil, 0, @SocketThread, Info, 0, ThreadId);
if hClientThread <> 0 then CloseHandle(hClientThread);
end;
until false;
finally
CloseSocket(ListenSocket);
end;
finally
WSACleanup;
end;
//------------------------------------------------------------------------------
end.
DVM (2008-01-13 21:06:00) [50]
> в какую сторону хотя бы смотреть...
в сторону либо потоков либо в сторону асинхронных сокетов на сообщениях.
Для блокирующих сокетов Accept крутить в цикле (в идеале цикл в отдельном потоке), при подключении клиента создавать новый поток - передавать туда сокет и работать с конкретным клиентом в этом потоке.