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

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

Как правильно написать socks-сервер? [D7, WinXP]


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

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 крутить в цикле (в идеале цикл в отдельном потоке), при подключении клиента создавать новый поток - передавать туда сокет и работать с конкретным клиентом в этом потоке.


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

Наверх

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