Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Hello, World!
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  06:19[Войти] | [Зарегистрироваться]

Обсуждение материала
Использование сокетов в Delphi. Часть вторая: сокеты Windows
Полный текст материала


Другие публикации автора: Антон Григорьев

Цитата или краткий комментарий:

«... В предыдущей статье цикла «Использование сокетов в Delphi» мы рассмотрели те методы работы с сокетами, которые восходят ещё к сокетам Беркли. Разработчики библиотеки сокетов для Windows добавили в неё также поддержку новых методов, упрощающих работу с сокетами для приложений, имеющих традиционную для Windows событийно-ориентированную модель. В Windows можно использовать асинхронные сокеты и перекрытый ввод-вывод. ...»


Важно:
  • Страница предназначена для обсуждения материала, его содержания, полезности, соответствия действительности и так далее. Смысл не в разборке, а в приближении к истине :о) и пользе для всех.
  • Любые другие сообщения или вопросы, а так же личные эмоции в адрес авторов и полемика, не относящаяся к теме обсуждаемого материала, будут удаляться без предупреждения авторов, дабы не мешать жителям нормально общаться.
  • При голосовании учитывайте уровень, на который расчитан материал. "Интересность и полезность" имеет смысл оценивать относительно того, кому именно предназначался материал.
  • Размер одного сообщений не должен превышать 5К. Если Вам нужно сказать больше, сделайте это за два раза. Или, что в данной ситуации правильнее, напишите свою статью.
Всегда легче осудить сделанное, нежели сделать самому. Поэтому, пожалуйста, соблюдайте правила Королевства и уважайте друг друга.



Добавить свое мнение.

Результаты голосования
Оценка содержания

  Содержит полезные и(или) интересные сведения
[1]18100%
 
  Ничего особенно нового и интересного
[2]00%
 
  Написано неверно (обязательно укажите почему)
[3]00%
 
Всего проголосовали: 18

Оценка стиля изложения

  Все понятно, материал читается легко
[1]1191.7%
 
  Есть неясности в изложении
[2]18.3%
 
  Непонятно написано, трудно читается
[3]00%
 
Всего проголосовали: 12




Смотрите также материалы по темам:
[UDP] [WinSocket]

Комментарии жителей
Отслеживать это обсуждение

Всего сообщений: 39

12-02-2012 05:53
Спасибо Антону еще раз за эти статьи. Обнаружил интересное обстоятельство. Разбирался с использованием событий сокетов, обнаружил, что если мы создаем событие, "подключаем" его к событию подключения сокета, и вызываем connect (безо всяких своих дополнительных потоков (нитей)), то при этом у процесса появляется еще один поток. Даже если закрыть сокет, поток остается, если вызвать WSACleanup(), то он исчезает. Видимо библиотека сокетов Ws2_32.dll сама создает этот поток.

Код: создали сокет, задали адрес и порт, потом

  ConnectEvent := WSACreateEvent();
  WSAEventSelect(ClientSocket, ConnectEvent, FD_CONNECT);
  Result := connect(ClientSocket, Addr, SizeOf(Addr)); // вот тут возникает еще один поток



Если событие даже и создать, но не использовать (незачем его создавать конечно в таком случае), то поток не возникает

  ConnectEvent := WSACreateEvent();
// WSAEventSelect(ClientSocket, ConnectEvent, FD_CONNECT); закомментируем эту строку
  Result := connect(ClientSocket, Addr, SizeOf(Addr)); // тогда тут поток не возникает




08-02-2011 09:11
По материалам данной статьи я сделал специфический сервис для чтения SNMP пакетов. SNMP пакеты с точки зрения системы являются простыми UDP пакетами. Специфика заключалась в отправке и приеме 70000 пакетов. Причем необходимо было сделать скользящее окно одновременной отправки не более 100 пакетов. И тут я увидел информацию по перекрытому вводу-выводу с использованием процедур завершения. На этой основе я и построил свою программу. Что хотелось бы отметить:
1) Несмотря на то что процедура завершения выполняется в том же потоке, что вызвавший ее поток, необходимо защищать переменные.
2) Процедура SleepEx(n, True) выполняется без задержки!
У меня пакеты могут не придти или придти с опозданием.



13-09-2010 03:51
Извиняюсь, недогляд, FD_CONNECT там не придет, т.к. не было Select-а для этого события.

Общности ради хотелось бы уточнить верно ли это утверждение:
Для слушающего сокета могут прийти только события FD_ACCEPT. Для подключенного сокета все события кроме FD_ACCEPT.


13-09-2010 03:48
Проверка наверное все таки нужна я так полагаю. Если мы на слушающем сокете при входящем подключении сделаем accept, то созданный сокет пронаследует все "настройки" слушающего, и будет асинхронным и все события будут посылаться в это же окно с тем же сообщением. Следовательно в оконную функцию придет FD_CONNECT который вполне может завершиться неудачей, и нужно будет закрыть сокет.


13-09-2010 02:31
сообщение от автора материала
Shoor:

Сейчас, если честно, не могу вспонить, зачем я написал эту проверку. Никакого вызова сокетной функции, которая могла бы установить такую ошибку, перед этим нет, сокет передаётся уже готовым и заносится в переменную простым приведением типа. Подозреваю, что эту проверку я вставил на автомате, а на самом деле она тут не нужна вообще. По крайней мере, в справке по WSAAsyncSelect я не заметил указаний на необходимость такой проверки. Более того, по логике вещей WSAGetLastError не сможет здесь вернуть правильную ошибку - мало ли какие сокетные функции вызывались в промежутке между постановкой сообщения в очередь и его обработкой. Наверное, лучше всего выкинуть эту проверку вообще.


12-09-2010 15:25
хотелось бы уточнить относительно вот этого кода в статье:

procedure TForm1.WMSocketEvent(var Msg:TMessage);
var Sock:TSocket;
     SockError:Integer;
  begin
   Sock:=TSocket(Msg.WParam);
   SockError:=WSAGetSelectError(Msg.lParam);
   if SockError<>0 then
    begin
     // Здесь должен быть анализ ошибки
     CloseSocket(Sock);
     Exit
    end;
   case WSAGetSelectEvent(Msg.lParam) of
    FD_Read:
     begin
      // Пришёл запрос от клиента. Необходимо прочитать данные,
      // сформировать ответ и отправить его.
     end;
    FD_Accept:
     begin
      // Просто вызываем функцию Accept. Её результат нигде не
      // сохраняется, потому что вновь созданный сокет автоматически
      // начинает работать в асинхронном режиме, и его дескриптор при
      // необходимости будет передан через Msg.wParam при возникновении
      // события
      Accept(Sock,nil,nil)
     end;
    FD_Close:
     begin
      // Получив от клиента сигнал завершения, сервер, в принципе,
      // может попытаться отправить ему данные. После этого сервер
      // также должен соединение со своей стороны
      Shutdown(Sock,SD_Send);
      CloseSocket(Sock)
     end
   end
  end;



мы сразу закрываем сокет:

   if SockError<>0 then
    begin
     // Здесь должен быть анализ ошибки
     CloseSocket(Sock);
     Exit
    end;


хотя поидее в значении Sock может быть и слушающий сокет. Не знаю возникают ли ошибки при FD_ACCEPT но мне кажется неправильно вот так вот закрывать сокет, сначала надо бы отфильтровать FD_ACCEPT. Если не прав - поправьте.


18-05-2010 09:47
Антон, огромное спасибо статья содержит весьма практические сведения !
менее чем за час удалось разобраться с неблокируемым режимом!

семью строками кода удалось запустить клиент !
с WSAStringToAddress, наверно и того меньше будет :)

  
  WSAStartup($101, Data);
  ClientSock := Socket(AF_Inet, Sock_Stream, 0);
  addr.sin_family := AF_INET;
  addr.sin_addr.s_addr := inet_addr(PAnsiChar('94.100.177.6')); //   htonl(INADDR_ANY);
  addr.sin_port := htons(110);
  connect(ClientSock, addr, sizeof(sockaddr_in));
  WSAAsyncSelect(ClientSock, Handle, WM_SocketEvent, FD_Read or FD_Accept or FD_Close);




также не составило особого труда разобраться и запустить обработчик из вашего примера!

после вашей статьи сложилось впечатление, что документация из официальных источников специально вводит людей в заблуждения чтоб они никогда не смогли сами разобраться с теперь уже очевидными вещами, подтверждению этому куча ненужных примеров идущих в комплекте с дельфи, и как вы сами заметили отсутствие важных прототипов функций таких как  WSAStringToAddress и.др...  


02-02-2010 13:28
сообщение от автора материала
Какие еще есть более производительные способы.

Они описаны во второй части статьи. Правда, там не описаны порты завершения ввода-вывода, которые являются самым производительным, ориентированным на массовое обслуживание клиентов средством, но после приведённой там информации вы с этим разберётесь самостоятельно.


02-02-2010 13:18
В этом абзаце:
"Преимущество такого сервера по сравнению с сервером, основанным на функции Select (пример кода такого сервера приведён в предыдущей статье), заключается в том, что при отсутствии событий на сокетах он не находится в приостановленном режиме и может выполнять какие-то другие действия (например, реагировать на действия пользователя). Кроме того, этот сервер не имеет ограничений по количеству подключаемых клиентов, связанных с размером типа TFDSet. Впрочем, последнее не является существенным преимуществом, так как при таком количестве клиентов сервер обычно использует другие, более производительные способы взаимодействия с клиентами."

Хотелось бы узнать подробности по последнему предложению. Какие еще есть более производительные способы. А так же интерсно бы услышать какие методы
наиболее удачны по отражению DoS-атак. Хотя на мой взгляд имется в этом вопросе принципиальная проблема. С одной стороны сервер должен максимально быстро обслуживать клиентов, а это как раз "улучшает" DoS-атаку :)


14-12-2009 13:08
сообщение от автора материала
Hunter Black:

За неимением сети попробовал локально - всё работает. На форме лежит кнопка с вот таким обработчиком:

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  S:TSocket;
  Addr:TSockAddr;
begin
  TAcceptThread.Create(False);
  S:=Socket(AF_Inet,Sock_Stream,0);
  Addr.sin_family:=PF_Inet;
  Addr.sin_addr.S_addr:=Inet_Addr('127.0.0.1');
  Addr.sin_port:=HtoNS(3320);
  FillChar(Addr.sin_zero,SizeOf(Addr.sin_zero),0);
  Connect(S,Addr,SizeOf(Addr));
  Sleep(1000);
  CloseSocket(S)
end;



Нить TAcceptThread описана так:

type
  TAcceptThread = class(TThread)
  private
    FS:array of Byte;
    St:string;
  protected
    procedure ShowFS;
    procedure Execute; override;
  end;

...

function TestAccept(
lpCallerId,lpCallerData:PWSABuf;
lpSQOS,lpGQOS:Pointer;
lpCalleeID,lpCalleeData:PWSABuf;
g:Pointer;
dwCallbackData:DWORD):Integer;stdcall;
var
  Thread:TAcceptThread;
begin
  Thread:=TAcceptThread(dwCallbackData);
  SetLength(Thread.FS,lpCallerId.Len);
  Move(lpCallerId.Buf^,Thread.FS[0],lpCallerId.Len);
  Result:=1
end;

{ TAcceptThread }

procedure TAcceptThread.Execute;
var
  S:TSocket;
  Addr:TSockAddr;
  Sz:Integer;
  I:Integer;
begin
  S:=Socket(AF_Inet,Sock_Stream,0);
  Addr.sin_family:=PF_Inet;
  Addr.sin_addr.S_addr:=InAddr_Any;
  Addr.sin_port:=HtoNS(3320);
  FillChar(Addr.sin_zero,SizeOf(Addr.sin_zero),0);
  Bind(S,Addr,SizeOf(Addr));
  Listen(S,SoMaxConn);
  Sz:=SizeOf(Addr);
  WSAAccept(S,@Addr,@Sz,TestAccept,DWORD(Self));
  CloseSocket(S);
  for I:=0 to High(FS) do
    St:=St+IntToStr(FS[I])+' ';
  Synchronize(ShowFS)
end;

procedure TAcceptThread.ShowFS;
begin
  ShowMessage(St)
end;



Цифры 127.0.0.1 в возвращаемом результате хорошо видно.


14-12-2009 04:39
При использовании функции WSAAccept и параметра LPCONDITIONPROC, возникает следующая проблема. Параметры callback-функции lpCallerId и lpCalleeId всегда и с любого компа возвращают IP-адреса "0.0.0.0". В чем может быть проблема?


25-05-2008 17:25
хорошие статьи. ждем продолжения :)


18-05-2008 03:12
Надеюсь, про третью часть это не шутка была, и она вот-вот появится?.. ;-)


28-06-2007 03:08
Антон , а можно примерчики, выложит где-нибудь.


28-06-2007 03:05
Вот ссылка кто че скажет по поводу.
http://www.felix-colibri.com/papers/web/socket_programming/socket_programming.html


13-06-2007 22:14
Эх, когда же наступит 1 декабря 2009 года...Ну хотя бы 30 сентября 2008....


23-03-2007 07:37
Отличные статьи, большое спасибо автору


21-03-2007 15:54
Огромное спасибо за инфо.


20-02-2007 11:45
Событие ведь не сообщения - количество SetEvent узнать невозможно, поэтому в MSDN и пишут про атомарность WSAEnumNetworkEvents

Спасибо, теперь понятно.


20-02-2007 07:18
второй параметр этой фнкции можно же и не заполнять, сбросив событие вручную после обработки всех сокетов.
Ну так вы его сбросите, а оно может во время обработки WSAEnumNetworkEvents кем-то другим выставится. Событие ведь не сообщения - количество SetEvent узнать невозможно, поэтому в MSDN и пишут про атомарность WSAEnumNetworkEvents, иначе второй параметр был бы вообще не нужен, сами бы сбросили через ResetEvent.
 DRON


19-02-2007 12:57
Только один, так как иначе не обеспечить нормальную работу WaitFor* функции и WSAEnumNetworkEvents - будет потеря некоторых событий.

Почему? Данные для WSAEnumNetworkEvents ведь вроде берутся из сокета, а не из события; второй параметр этой фнкции можно же и не заполнять, сбросив событие вручную после обработки всех сокетов.


19-02-2007 12:38
И ещё, сколько сокетов могут быть связаны с одним событием, только один или несколько?
Только один, так как иначе не обеспечить нормальную работу WaitFor* функции и WSAEnumNetworkEvents - будет потеря некоторых событий. Вам придётся проходить по всем сокетам ипользующим этот Event и вызывать WSAEnumNetworkEvents, так вот в промежутке между вызовами Event может выставится другим сокетом и вы потеряете какое нибудь событие.
 DRON


19-02-2007 12:02
Спасибо за стати.

Есть некоторые неясности в работе асинхронных скоетов, которые, думаю, следует уточнить в статье:

Если необходимо использовать асинхронный сокет в блокирующем режиме, после вызова WSAAsyncSelect требуется перевести его в этот режим вручную.

Вот в MSDN пишут:

The WSAAsyncSelect function automatically sets socket s to nonblocking mode, regardless of the value of lEvent. To set socket s back to blocking mode, it is first necessary to clear the event record associated with socket s via a call to WSAAsyncSelect with lEvent set to zero. You can then call ioctlsocket or WSAIoctl to set the socket back to blocking mode. For more information about how to set the nonblocking socket back to blocking mode, see the ioctlsocket and WSAIoctl functions.

The WSAEventSelect function automatically sets socket s to nonblocking mode, regardless of the value of lNetworkEvents. To set socket s back to blocking mode, it is first necessary to clear the event record associated with socket s via a call to WSAEventSelect with lNetworkEvents set to zero and the hEventObject parameter set to NULL. You can then call ioctlsocket or WSAIoctl to set the socket back to blocking mode.

Так вот вопрос: таки можно ли работать в асинхронном режиме с блокирующим сокетом или нет?
Если да, то думаю в статье стоит указать что это несмотря на противоречие с MSDN.
Блокирующий асинхронный режим, думаю, можно было бы применить так: accept и recv можно вызывать по FD_xx событиям, а send пусть блокирует, тогда мы, как в примерах, не учитываем FD_WRITE, но уверены что данные не потеряютя при переполнении буфера.

И ещё, сколько сокетов могут быть связаны с одним событием, только один или несколько ? В MSDN информации на этот счёт не нашёл.


14-01-2007 00:44
сообщение от автора материала
Узкое место передачи данных через сеть - это именно сама передача, а не то, как организована работа с буфером в памяти, в который эти данные поступили. Так что используйте такие способы работы с сокетами, которые вам удобнее.


13-01-2007 05:13
Есть ли какая-нибудь информация о производительности Windows Sockets vs Berkley Sockets? Какие сокеты лучше использовать при написании высоко-производительных приложенй? Скажем, есть необходимость очень быстро обойти много сайтов и что-нибудь скачать. Какие вообще есть рекомендации по повышению производительности в таком случае? И есть ли смысл использовать асинхронные сокеты или лучше использовать много потоков, в каждом - блокирующий сокет.


12-12-2006 04:06
Спасибо Антону за подробную статью.
Я тоже с нетерпением жду третьей части :), а примери будут?


01-12-2006 06:22
сообщение от автора материала
Но нельзя ли в дополнение к ней представить образцы полнофункциональных клиента и сервера на Winsock2? Это бы очень помогло для обучения "методом научного тыка" ;)

Это готовится. Уже пять примеров готово (правда, комментарии в коде пока не расставлены), постепенно готовлю остальные.


01-12-2006 06:14
Спасибо за содержательные публикации, Антон

Но нельзя ли в дополнение к ней представить образцы полнофункциональных клиента и сервера на Winsock2? Это бы очень помогло для обучения "методом научного тыка" ;)


29-11-2006 06:47
спасибо!


07-11-2006 04:48
Если программа выполняет одновременно несколько операций перекрытого ввода-вывода, встаёт вопрос, как при вызове процедуры завершения определить, какая из них завершилась. Для каждой такой операции должен быть создан уникальный экземпляр структуры TWSAOverlapped. Процедура завершения получает указатель на тот экземпляр, который использовался для начала завершившейся операции. Можно сравнить указатель с теми, которые использовались для запуска операций перекрытого ввода-вывода, и определить, какая из них завершилась. Это не всегда бывает удобно из-за необходимости где-то хранить список указателей, использовавшихся для операций перекрытого ввода-вывода. Существуют ещё два варианта решения этой проблемы. Первый вариант заключается в создании своей процедуры завершения для каждой из выполняющихся параллельно операций. Этот вариант приводит к получению громоздкого кода и может быть неудобен, если число одновременно выполняющихся операций заранее неизвестно. Его следует использовать только при одновременном выполнении разнородных опреаций, требующих разных алгоритмов при обработке их завершения. Другой вариант предлагается в MSDN'e. Так как при использовании процедур завершения значение поля hEvent структуры TWSAOverlapped игнорируется системой, программа может записать туда любое 32-битное значение и с его помощью определить, какая из операций завершена. В строго типизированном языке, каким является Паскаль, подобное смешение типа дескриптора и целого выглядит весьма непривлекательно, но, к сожалению, это лучшее из того, что нам предлагают разработчики WinSock API.

Встречал еще один вариант:
Вместо структуры TWSAOverlapped использовать свою TWSAOverlappedEx, расширенную необходимыми параметрами, только при передаче указателя на нее, приводить к типу PWSAOverlapped. Также в Паскале смотриться некрасиво...
 Ins


11-10-2006 04:58
Ну и когда же 3-я часть бум?


09-12-2005 10:14
Хорошо написано)
з.ы. А полгода-то прошло)
Сообщение не подписано


08-12-2005 13:24
Очень хорошо, но хотелось полнее. Уж не просто самому разобраться. Без этой статьи у меня бы совсем ничего не получилось... Пытаюсь написать майлер, чтобы отправлял письма по SMTP. Пишу на SP-FORT'е, это очень интересно.
Сообщение не подписано


23-11-2005 11:22
порядочное кол-во описок и недочетов.
детально расписывать не буду, но например:
"Параметр lpCalleeId содержит адрес интерфейса, принявшего соединение (поля структуры при этом используются так же, как у параметра lpCallerId). В предыдущей статье обсуждалось, что сокет, привязанный к адресу InAddr_Any, прослушивает все сетевые интерфейсы, имеющиеся на компьютере, но каждое подключение, созданное с его помощью, использует конкретный интерфейс. Параметр lpCalleeId содержит адрес, привязанный к конкретному соединению. Параметр lpCalleeData указывает на буфер, в который сервер может положить данные для отправки клиенту. Этот параметр также не имеет смысла при использовании протокола TCP, не поддерживающего отправку данных при соединении."
не работает это. всегда будет тот-же адрес что и при bind(), т.е. если был указан inaddr_any то и интерфейс будет inaddr_any. Увы. Проверялось на NT4 и Win2K.



01-09-2005 11:08
Хотелось-бы услышать про использование IOCompletionPort в сочетании с overlapped IO - вроде как это самый производительный способ построения TCP серверов.

Вот тут есть http://lib.training.ru/Lib/ArticleDetail.aspx?ar=1699&l=&mi=100&mic=305

Немного, и по английски


13-07-2005 07:39
ждем третью часть. спасибо.
Сообщение не подписано


30-03-2005 07:48
сообщение от автора материала
Шансы есть, но не раньше, чем через полгода - сейчас мне пока не до этого.


30-03-2005 07:21
Антон!
У нас есть шансы все-таки увидеть третью часть или как? :)

С уважением,
Василий.


21-10-2004 16:34
Спасибо Антону за подробную статью.
С нетерпением жду третьей части :)


Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Жил-был у бабушки серенький КТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.

Оценка содержания
 
Содержит полезные и(или) интересные сведения
 
Ничего особенно нового и интересного
 
Написано неверно (обязательно укажите почему)


Оценка стиля изложения
 
Все понятно, материал читается легко
 
Есть неясности в изложении
 
Непонятно написано, трудно читается

Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования