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

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

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


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

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

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

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

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

 
   
С Л С

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

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

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

Квинтана

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

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

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

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

 
  
АРХИВЫ

 
 

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

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


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

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

«... Данная статья является первой в цикле из трёх статей, призванных дать ответы на подобные вопросы. Она посвящена стандартным сокетам. ...»


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



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

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

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

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

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




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

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

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

29-03-2017 04:09
Отличная статья, всё очень доступно и понятно!
В Вашем примере из книги к этой теме UDPChat, вроде всё посылается и принимается, но когда собираем под XE сообщения приходят обрезанные и немного изменённые в конце, видимо из-за юникода, не подскажите как это поправить?


21-01-2016 13:38
Очередной раз обратился к этой статье, чтобы освежить знания, наскочил на несколько незначительных багов, считаю нужным рассказать:
(обычно это 255.255.255.255, но в некоторых случаях могут использоваться адреса типа 192.168.100.225 для вещания в пределах сети 192.168.100.ХХ и т.п.) - адрес должен быть 192.168.100.255.
Напомним, что дейтаграммы могут поступать в буфер не в том порядке, в котором они были отправлены. Кроме того, буфер может содержать - дальше идет непонятный перевод строки... видимо, ошибка при публикации.
В общем случае разработчик сервера сам должен выбрать порт из диапазона 1024-65535 - никак не могу согласиться. Я, например, создаю Web сервер, потому выбираю стандартный для HTTP порт - 80.
мои эксперименты показали, что функция S всегда либо копирует - функция Send, тут просто опечатка.


21-01-2016 13:37
Очередной раз обратился к этой статье, чтобы освежить знания, наскочил на несколько незначительных багов, считаю нужным рассказать:
(обычно это 255.255.255.255, но в некоторых случаях могут использоваться адреса типа 192.168.100.225 для вещания в пределах сети 192.168.100.ХХ и т.п.) - адрес должен быть 192.168.100.255.
Напомним, что дейтаграммы могут поступать в буфер не в том порядке, в котором они были отправлены. Кроме того, буфер может содержать - дальше идет непонятный перевод строки... видимо, ошибка при публикации.
В общем случае разработчик сервера сам должен выбрать порт из диапазона 1024-65535 - никак не могу согласиться. Я, например, создаю Web сервер, потому выбираю стандартный для HTTP порт - 80.
мои эксперименты показали, что функция S всегда либо копирует - функция Send, тут просто опечатка.


02-03-2012 01:38
>>> В оригинале параметры From и FromLen передаются как указатели, и программа может
>>> использовать вместо них нулевые указатели, если её не интересует адрес отправителя.
>>> Разработчики модуля WinSock заменили указатели параметрами-переменными, что в большинстве
>>> случаев удобнее. Однако возможность передавать нулевые указатели при этом оказалась >>> потерянной.

Все же можно:


  RecvFrom(H, Buf, 1024, 0, TSockAddr(nil^), LongInt(nil^));

 exo


15-05-2011 08:37
Очень хорошо!!
Сеть может связывать разные аппаратные платформы, поэтому требуется согласование форматов передаваемых данных, в частности - форматов целых чисел. Двухбайтные целые числа хранятся в памяти в двух последовательно расположенных байтах. При этом возможны два варианта: в первом байте хранится младший байт числа, а во втором - старший, и наоборот. Способ хранения определяется аппаратной частью платформы. Процессоры Intel используют первый вариант, т.е. первым хранится младший байт, а другие процессоры (например, Motorola) - второй вариант.
Как быть, если серверное приложение пишется для OS Windows, а клиентское как Java midlet, для телефонов, где тип процессора просто не угадаешь? И ещё какой тип сокетов для такой связки стоит использовать?

Спасибо.


17-05-2010 20:53
сообщение от автора материала
Connect(S,...); осуществляется, но возвращает ошибку!? это так и должно быть ?

В неблокирующем режиме - да. Точно так же, как, например, recv - ошибку WSAEWOULDBLOCK.

и если можно расскажите пожалуйста каким образом можно организовать получение сообщений например о том что в буфер поступили новые данные...

Это разбирается во второй статье цикла, см. ссылку в конце.

и как принимать длинные данные (в 2 и более раз длиннее буфера приема) которые только в конце заканчиваются флагом PUSH...  как узнать что PUSH поступил ?

Никакие низкоуровневые флаги на уровне сокетов вы не увидите. А TCP- вообще потоковый протокол, данные могут разбиваться и склеиваться системой как угодно. Так что вы должны в своём протоколе самостоятельно предусмотреть тот или иной признак окончания блока данных и проверять его.


17-05-2010 15:09
Спасибо за статью!

Есть маленький вопрос, можно ли чуть поподробнее о неблокируемом режиме ?

например после IOCtlSocket(S,FIONBIO,Block);
Connect(S,...); осуществляется, но возвращает ошибку!? это так и должно быть ?

if IsSet(S,SetW) then  // IsSet что это за функция - FD_IsSet ???
   // Connect выполнен успешно
  else if IsSet(S,SetE) then
   // Соединиться не удалось
  else
   // Произошла ещё какая-то ошибка

///
и если можно расскажите пожалуйста каким образом можно организовать получение сообщений например о том что в буфер поступили новые данные...

и как принимать длинные данные (в 2 и более раз длиннее буфера приема) которые только в конце заканчиваются флагом PUSH...  как узнать что PUSH поступил ? предположим если оканчивать прием, если пришло данных меньше максимального значения буфера приема, а если они равны и это была последняя часть с флагом PUSH ?  


20-11-2009 13:29
Спасибо за статью


26-10-2009 08:40
Супер! Все просто і ясно!


12-04-2009 02:37
Супер статья, сокеты выучил, за одно прочтение, до этого с ними был не знаком.


24-07-2008 15:54
Вот это разжевано!!! Раньше не хотел связываться с сетью, сокетами и т.п. а как прочитал статью... В общем, автору ОГРОМНОЕ человеческое спасибо и рэспект от всей души!!!


25-05-2008 13:40
Добрый день, статья очень познавательная, но вот на практике столкнулся с такой проблемой: необходимомо передать широковещательный пакет максимального размера, так как макс. размер дейтаграммы для UDP равен 65507 , так при послыке UDP пакета дейтаграмма доходит до назначения, кода же пытаюсь отослать эти же данные спомощью опции Broadcast то данные больше 1000 непроходят.

Думаю может дело с настройками сети, или еще с чем то? и вообще может есть какое то ограничение жесткое?


19-05-2008 15:48
Огромное СПАСИБО за статью: написано очень подробно, а главное - доступно. Очень помогла в процессе разработки курсового проекта.


11-05-2008 03:21
Автору большое спасибо за труд по написанию данной статьи!
Эта статья станет стартовой для меня в изучении работы с сетью без компонентов после того, как научился работать с WinAPI и создавать программы на уровне API.


04-06-2007 10:05
У меня с этими сокетами сложилась смешная ситуация. У меня задача - проще не придумаешь. Мне нужен клиент. От него требуется передавать и принимать пакеты информации. Я написал программу по материалам статьи. На локальной машине (то есть клиент соединяется по адресу 127.0.0.20) все чудненько работает. Когда же пытаюсь проделать то же самое через сеть, то сервер пакеты принимает, а клиент зацикливается на приеме пакетов нулевой длины. Ладно, думаю, используем классику. Написал клиента на стандартном TCPClient из вкладки Internet Delphi 7. И что же? Да примерно то же самое. Передает чудненько, а событие OnReceive просто не наступает. Конечно, немного радует, что хоть не циклится программа, но эта радость довольно слабая и не перекрывает горя от осознания того, что намеченная цель так и не достигнута. Может кто-нибудь помочь в этой странной ситуации? Эта компонента TCPClient вообще работает у кого-нибудь?


04-06-2007 09:41
Не хватает примера полного текста программы, самой простой (передачи от клиента на сервер и обратно сообщения "Привет"), чтобы эту программу можно было просто откомпилиравать, запустить и посмотреть, как она работает. Во всем остальном можно уже тренироваться на этой программе.


01-03-2007 01:24
Хочу просто добавить свою оценку. Прикольная статья. Давно работаю с сокетами, но был кошмарный пробел при отработке разрывов связи... Понравилось, что рекомендуется как правильно организовать обмен.


15-02-2007 18:56
Сделано ли так в реализациях WinSock 2 для всех верисй Windows?
Каких именно хендлов это касается, только сокетов или и других?
Где можно почитать про аллокатор хендлов?

Эх... я и сам не прочь получить ответы на эти вопросы, в документации об этом я никакой информации не встречал. А по поводу хендлов когда-то очень давно читал некую статью, возможно на WASM.RU, но точно не помню. Так что железных доказательств у меня нет, но практические опыты и копание в чужих исходниках показывает что всё именно так как я написал (и не только под виндами).
Например данный способ используется в Indy и Миранде. Ваш метод с Select-ом тоже активно применяется. Лично я предпочитаю вариант который предложил Антон Григорьев, только не событие создаю, а очередь сообщений и использую MsgWaitForMultipleObjects.
 DRON


15-02-2007 13:26
Локатор хендлов в виндах устроен несколько сложнее чем вы думаете
Очень интересно, спасибо.
Сделано ли так в реализациях WinSock 2 для всех верисй Windows?
Каких именно хендлов это касается, только сокетов или и других?
Где можно почитать про аллокатор хендлов?


15-02-2007 11:46
Тот же дескриптор получить можно, дескрипторы таки используются повторно:
Да, но не в разных потоках. Локатор хендлов в виндах устроен несколько сложнее чем вы думаете: список освобождённых хендлов принадлежит потоку, а не процессу, поэтому хендлы в разных потоках не могут пересечься, правда после уничтожения потока его список переходит к главному потоку, но это в данном случае не важно.
Для проверки запустите следующий код:

var
  StopEvent,Event:THandle;
  Threads:array[0..9] of THandle;
  Sockets:array[0..9] of TSocket;

function SockProc(S:PHandle):Integer;
begin
  S^:=Socket(AF_INET,Sock_Stream,IPProto_TCP);
  CloseSocket(S^);
  SetEvent(Event);
  WaitForSingleObject(StopEvent,INFINITE);
end;

  StopEvent:=CreateEvent(nil,True,False,nil);
  Event:=CreateEvent(nil,True,False,nil);
  //SetEvent(StopEvent);
  for A:=0 to High(Threads) do begin
    S:=0;
    ResetEvent(Event);
    Threads[A]:=BeginThread(nil,0,@SockProc,@Sockets[A],0,Data);
    WaitForSingleObject(Event,INFINITE);
    Used:=False;
    for B:=0 to A-1 do
      if Sockets[A]=Sockets[ B] then begin
        Used:=True;
        Break;
      end;
    Memo1.Lines.Add(IfThen(Used,'!')+IntToStr(Sockets[A]));
  end;
  SetEvent(StopEvent);
  WaitForMultipleObjects(Length(Threads),@Threads,True,INFINITE);


Видно что хендлы не повторяются, а вот если убрать "//" то некоторые начнут повторяться (и то очень мало), так как связанных с ним потоков уже несуществует. Кстати этот локатор межпроцессорный, то есть в разных процессах хендлы тоже не будут повторяться.
 DRON


14-02-2007 13:07
Ничего не понял, какая третья нить, как может получиться сокет с тем же дескриптором?
Третья нить может быть, например, ещё одним сервером.
Тот же дескриптор получить можно, дескрипторы таки используются повторно:

  WSAStartup($101, Data);
  S1 := socket(AF_INET, Sock_Stream, IPProto_TCP);
  Memo1.Lines.Add(IntToStr(S1));
  closesocket(S1);
  S2 := socket(AF_INET, Sock_Stream, IPProto_TCP);
  Memo1.Lines.Add(IntToStr(S2));
  closesocket(S2);
  WSACleanup;


InterlockedExchange в данном случае не поможет. В Accept сокет передаётся по значению, т.е. копия значения. Если закрытие и открытия другого попадёт между копированием и фактическим вызовом (или внутри Accept но до начала ожидания), то никаким InterlockedExchange значение, переданное в accept, не изменить, и Accpet будет работать не с тем сокетом.

Я в таких случаях использую асинхронные сокеты на событиях.
Думаю это то, что мне нужно.
Тем не менее, хотелось бы также научится работать с обычными блокирующими сокетами (на которых, кстати, построена Indy, с которой я и хочу уйти).


14-02-2007 12:35
сообщение от автора материала
Как корректно остановить такой сервер?

Я в таких случаях использую асинхронные сокеты на событиях. Создаю сокет, связываю событие с его FD_ACCEPT, но также создаю ещё одно событие. Делаю бесконечный цикл с WSAWaitForMautipleEvents. Второе событие взвожу при необходимости из другой нити. По тому, какое событие возникло, определяю - то ли сработал FD_ACCEPT, то ли пора закругляться.


14-02-2007 12:11
но тут есть недостаток - closesocket из другой нити может попасть не на время ожидания accept, после чего третья нить создаёт новый сокет с тем же дескриптором, и уже этот новый сокет непреднамеренно попадает в accept.
Ничего не понял, какая третья нить, как может получиться сокет с тем же дескриптором? Попасть конечно может и не на ожидание, но тут достаточно аккуратной работы с переменными, например в приведённом мною примере за это отвечает InterlockedExchange и проверка на Terminated в Open.
Так, я пришел к варианту:
Можно конечно и так.
 DRON


14-02-2007 11:17
Выставить какой нибудь флажок (да хоть тот же TThread.Terminated) и прибить сокет с помощью CloseSocket, всё это из другого (например основного) потока конечно. В потоке Accept вывалится с ошибкой, но по флажку вы поймёте что это просто завершение работы и молча завершите поток.

Спасибо за ответ.
Я ещё сам поискал решения, находил этот вариант, но тут есть недостаток - closesocket из другой нити может попасть не на время ожидания accept, после чего третья нить создаёт новый сокет с тем же дескриптором, и уже этот новый сокет непреднамеренно попадает в accept.
Так, я пришел к варианту:

  while True do
  begin
    FD_Zero(ReadList);
    FD_Set(ReadList, Server);
    ExceptList := ReadList;
    
    Select(0, @ReadList, nil, @ExceptList, nil);
    
    EnterCriticalSection(ServerSocketSection)
    try
      if FTerminated then Break;
      if not FD_IsSet(ReadList, Server) then
        Break;
      AcceptedSock := Accept( ... ); // здесь уже блокирования не будет
    finally
      LeaveCriticalSection(ServerSocketSection)
    end;
    if AcceptedSock = INVALID_SOCKET then
      Break
    else
      BeginThread( Connectionthread , AcceptedSock , ...);
  end;

При этом, остановка из другой нити выглядит так:

    EnterCriticalSection(ServerSocketSection)
    try
      FTerminated := True;
      CloseSocket(Server);
    finally
      LeaveCriticalSection(ServerSocketSection)
    end;

Насколько всё это правильно и оправдано? Действительно ли возможно после закрытия сокета появление другого сокета с тем же дескриптором?


14-02-2007 10:00
Как корректно остановить такой сервер?
Выставить какой нибудь флажок (да хоть тот же TThread.Terminated) и прибить сокет с помощью CloseSocket, всё это из другого (например основного) потока конечно. В потоке Accept вывалится с ошибкой, но по флажку вы поймёте что это просто завершение работы и молча завершите поток.
Вот тут было нечто работающее по такому принципу (клиент правда, а не сервер):
http://www.delphikingdom.com/asp/answer.asp?IDAnswer=44786
 DRON


14-02-2007 07:57
Есть неясность в работе Accept с блокирующими сокетами. Допустим, имеется серверный сокет, постоянно ожидающий новых клиентов:

function ServerThread( ... ): Integer;
  ...
begin
  ...
  while True do
  begin
    AcceptedSock := Accept( ... );
    if AcceptedSock = INVALID_SOCKET then
      Exit
    else
      BeginThread( Connectionthread , AcceptedSock , ...);
  end;
  ...
end;



Как корректно остановить такой сервер?


23-06-2006 02:33
сообщение от автора материала
Скажите пожалуйста, если например, нужно отправить широковещательный пакет из адреса 10.10.10.10 в сеть 192.168.100.* как определить число роутеров?

Спросить у админа :) А вообще, действовать по принципу traceroute - увеличивать TTL, пока не будет найден путь.

Возможно ли попадание широковещательного пакета в другую сеть при числе роутеров=0? В другую сеть - не через роутер? Это как?

И какие преимущества широковещательного пакета перед отправкой нужного пакета в цикле простым перебором IP-адресов в нужном диапазоне?

Меньшая нагрузка на сеть - вместо кучи пакетов идёт один, который ловится всеми.

Я хочу в своём приложении использовать UDP протокол, как я понимаю (и читал где-то) порт для сокета забивается приложением под себя и другие приложения не могут использовать его (иначе как приложения будут разделять свои пакеты?). Как можно тогда явно указывать порт, ведь он может быть занят? Тогда нужно предоставить системе выбрать свободный. Но как тогда на другом узле приложение узнает номер порта, которое выбрало приложение на нашем узле (ведь связь ещё не установлена)?

Явно указать порт можно с помощью Bind. Большинство приложений используют фиксированный порт, и если этот порт уже занят, просто не запускаются. Те, которые используют плавающий порт, придумывают специальные сервисы для передачи номера порта. Например, COM-сервер может использовать любой порт в диапазоне 1024-65535. Но есть системный Service Control Manager (SCM), который всегда использует 135-ый порт. Номер порта сервера удалёная машина узнаёт через SCM.

И на TCP протоколе у меня есть самописный клиент - забирает почту с mail.ru по порту 25, параллельно с ним может работать нормально Outlook - значит, для TCP порт забивается  под себя только сервером?

Тут вы просто перепутали порты клиента и сервера. Ваш клиент подключается к серверу, использующему 25-ый порт, но порт самого клиента при этом может быть любым. Ваш клиент использует один порт, Outlook - другой, просто оба они подключаются к одному серверу.


16-06-2006 17:45
Я хочу в своём приложении использовать UDP протокол, как я понимаю (и читал где-то) порт для сокета забивается приложением под себя и другие приложения не могут использовать его (иначе как приложения будут разделять свои пакеты?). Как можно тогда явно указывать порт, ведь он может быть занят? Тогда нужно предоставить системе выбрать свободный. Но как тогда на другом узле приложение узнает номер порта, которое выбрало приложение на нашем узле (ведь связь ещё не установлена)? И на TCP протоколе у меня есть самописный клиент - забирает почту с mail.ru по порту 25, параллельно с ним может работать нормально Outlook - значит, для TCP порт забивается  под себя только сервером?


16-06-2006 16:38
Скажите пожалуйста, если например, нужно отправить широковещательный пакет из адреса 10.10.10.10 в сеть 192.168.100.* как определить число роутеров? Возможно ли попадание широковещательного пакета в другую сеть при числе роутеров=0? Или что нужно сделать, чтобы широковещательный пакет попал в эту сеть? И какие преимущества широковещательного пакета перед отправкой нужного пакета в цикле простым перебором IP-адресов в нужном диапазоне?


22-05-2006 03:50
Спасибо за содержательный ответ. Просто на защите курсовой по хорошему каждую мелочь обьяснять надо, чем обусловлен выбор технологии и т.д.


22-05-2006 01:28
сообщение от автора материала
Solmir:

Ничего себе глупые вопросы - каждый на отдельную статью тянет :)

По второму сразу скажу - не знаю. С другими стеками просто не работал.

Коротко по первому: кроме сокетов, для передачи по сети можно использовать, например, именованные каналы (named pipes), почтовые ящики (mailslots), DCOM. Всё это основано, в конечном итоге, на тех же сокетах, но в данном случае все низкоуровневые сокетные операции скрыты в недрах системы. Достоинства - то, что все низкоуровневые операции берёт на себя система. Кроме того, так же прозрачно решаются вопросы авторизации доступа. Недостатки - если какая-то мелочь в организации обмена вас не устраивает, переделать её вы не сможете, а вот в с помощью сокетов вы управляете многими мелочами и можете выбирать такие протоколы верхнего уровня, которые вам наиболее удобны. А ещё сокеты - это кроссплатформенная технология, поддерживающаяся всеми операционными системами, поэтому с их помощью можно связываться, например, с контроллерами под управлением OS-9, а вот остальные средства имеют поддержку далеко не во всех ОС, да и в тех, где есть, по отзывам тех, кто пользовался, далеко не всегда хорошо работает.


21-05-2006 19:02
Безусловно полезная статья, но у меня возникло пара глупых вопросов:
Возможно ли осуществить передачу данных по сети без использования сокетов, если да то какими средствами, и преимущества этих средств.
Был рассмотрен стек протоколов TCP/IP, а какие стеки еще существуют, какие у них недостатки, преимущества по сравнению с TCP/IP.


28-11-2005 01:01
сообщение от автора материала
Beltar:

Пусть приходит запрос на соединение, как узнать IP-адрес пытающегося подключиться?

В функции Accept два последних параметра возвращают этот адрес.

Возможно, что нужно отказать клиету в соединении. Приходит на ум только установление соединения и его немедленное закрытие, или есть другие способы?

В рамках Berkely Sockets можно делать только так. Более красивый способ - использовать функцию WinSock WSAAccept. Она описана здесь: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1060


27-11-2005 07:26
Простите за возможно ламерский вопрос, но есть 2 неясности:

1) Пусть приходит запрос на соединение, как узнать IP-адрес пытающегося подключиться?

2) Возможно, что нужно отказать клиету в соединении. Приходит на ум только установление соединения и его немедленное закрытие, или есть другие способы?


30-09-2005 03:06
сообщение от автора материала
Александру:

Честно говоря, настолько глубоко с протоколом TCP я не разбирался, и однозначно ответить не могу. Хотя некоторые сомнения есть - в тестах, описанных в http://www.zeiss.net.ru/docs/technol/tcpip/tcp18.htm разрыв соединения обнаруживался быстрее - через 9.5 секунд. Однако, с другой стороны, это не может служить однозначным ответом, т.к. разработчики конкретной реализации TCP могут использовать дополнительные средства обнаружения потери связи сверх тех, что требует стандарт TCP. Например, реализация TCP в Windows не использует таймауты, если кабель к компьютеру не подключен.

Если вы хотите самостоятельно разобраться с тем, какие требования есть в стандарте, почитайте этот стандарт. Как его можно получить, описано в приложениях к http://www.mark-itt.ru/FWO/tcpip/


28-09-2005 03:58
Спасибо за эту статью. Хотелось бы прояснить один момент.

В главе "Протокол TCP" Вы пишете: "Если из-за неполадок в сети произошёл
разрыв связи, при попытке отправить данные или прочитать их клиент получит
отказ, а соединение будет разорвано".

Кем и когда будет разорвано соединение?

Допустим, произошел физический разрыв связи, например, вытащили из
устройства кабель Ethernet. Правильно ли я понимаю, что при этом в ответ
на запросы не будут приходить подтверждения ACK и через некоторое число
переповторов, повторяющихся через определенные тайм-ауты, программа,
реализующая стек TCP/IP, должна сама разорвать соединение?  Если это так,
то регламентируются ли каким-нибудь стандартом количества необходимых
переповторов и продолжительности тайм-аутов?

Я стокнулся с этой проблемой при тестировании одного преобразователя
RS-485/Ethernet. Соединение по TCP/IP разрывается через примерно 64
секунды, что для нас слишком много. Вот что  мне ответили в тех.поддержке:

- Isn't it possible to delete the old socket and create a new one after
several retries, not to wait 63.5 seconds?

- Sorry, this is standard TCP behauvier for retries. We have no parameter
to influence it. When an ACK is missing you have to retransmit the
packet after 0.5 sec, 1sec, 2sec, 4sec, 8sec, 16sec and 32sec. After this
time 63.5sec you should terminate the connection.

Кроме того, команда на принудительный разрыв соединения, которую я посылаю
со строны последовательного порта, по их словам, не может быть выполнена,
поскольку буфер TCP не пустой. Вот и приходится ждать более 1 минуты.

Эти утверждения вызывают у меня сомнения. Так ли это?
 alex


06-07-2005 04:56
сообщение от автора материала
Предыдущее сообщение - моё.


06-07-2005 04:54
Если происходит ожидание событий FD_READ or FD_CLOSE в асинхр. режиме на событиях, то вместо использования структуры типа TWSANetworkEvents будет ли быстрее просто вызывать Recv и смотреть на ее результат: если >0, то событие было FD_READ, в противном случае - FD_CLOSE ?

Так за этот промежуток может произойти два события - и FD_READ, и FD_CLOSE. А вы прочитаете данные из сокета и решите, что произошло событие FD_READ, а FD_CLOSE проигнорируете.

В случае использования асинх. режима, основаного на событиях так же как и в асинхр. режимена сообщениях возможна ситуация, когда Recv завершится с ошибкой WSAEWouldBlock?
(Вызывается WSAEnumNetworkEvents, выясняется что проихошло FD_READ, сокетное событие сбрасывается.
До вызова Recv еще раз происходит событие FD_READ. В итоге: сокетное событие взведено, а буфур пуст, так как Recv считала весь буфер)


Насколько я знаю, нет. Ложные срабатывания при использовании сообщений связаны с тем, что сообщение, помещённое в очередь нити, невозможно оттуда удалить. А событие можно сбросить. И если recv вызывается тогда, когда событие установлено, и буфер остаётся пустым, событие должно сброситься, что исключает ложное срабатывание.

Ложное срабатывание может возникнуть из-за неправильной синхронизации нитей. Например, в одной нити завершилось ожадание на WSAWaitForMultipleEvents по причине получения FD_Read, и в жтот момент квант времени получила другая нить, которая прочитала данные из этого сокета. Когда первая нить снова получит управление, окажется, что читать нечего, и с её точки зрения это будет ложным срабатыванием.
Сообщение не подписано


28-06-2005 05:18
1) Если происходит ожидание событий FD_READ or FD_CLOSE в асинхр. режиме на событиях, то вместо использования структуры типа TWSANetworkEvents будет ли быстрее просто вызывать Recv и смотреть на ее результат: если >0, то событие было FD_READ, в противном случае - FD_CLOSE ?

2)В случае использования асинх. режима, основаного на событиях так же как и в асинхр. режимена сообщениях возможна ситуация, когда Recv завершится с ошибкой WSAEWouldBlock?
(Вызывается WSAEnumNetworkEvents, выясняется что проихошло FD_READ, сокетное событие сбрасывается.
До вызова Recv еще раз происходит событие FD_READ. В итоге: сокетное событие взведено, а буфур пуст, так как Recv считала весь буфер)

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


09-06-2005 09:48
Если б я выложил код, все стало б на свои места.
Выкладывать его здесь-это немного не в тему. Как сдам сессию, выложу его на  Круглом столе.


08-06-2005 02:24
к Nobodyx:

А зачем созданным потокам обращаться к главному потоку в PortMapper-е? поток просто тупо форвардит с одного сокета на другой(им созданый), и для этого совершенно ненужна никакая дополнительная информация(кроме входящего сокета).
Короче неясно чего ты хочешь от программы.


08-06-2005 02:16
сообщение от автора материала
Возможно мне не следует оставлять здесь сообщения, которые наврядли заинтересуют посетителей?

Да, мы как-то уж очень в сторону ушли. Лучше задайте вопрос на Круглый стол, это будет уместнее. Там же разместите небольшой кусок кода, который вызывает проблемы, и подробно опишите, в чём эта проблема заключается. Там и поговорим. И, думаю, не только мы вдвоём - другие посетители тоже присоединятся.


07-06-2005 12:37
Еще раз пересмотрел код. Все так, как я и говорил. Могу выслать сорсы.

Цитата:
********
Не понимаю, что может потоку помешать, если он имеет указатель на объект. Надо только не забывать синхронизировать обращения.
********
Что-то все-таки мешает:(
Ума не приложу в чем может быть дело.
Если процедура не вложена та же история.

Возможно мне не следует оставлять здесь сообщения, которые наврядли заинтересуют посетителей?


07-06-2005 03:10
сообщение от автора материала
Мой вопрос состоит в том, почему поток, создаваемый методом класса, не может обращаться к полям класса?

Может. Не понимаю, что может потоку помешать, если он имеет указатель на объект. Надо только не забывать синхронизировать обращения.

Одна деталь: внутри метода описана процедура, которую сам метод и запускает в потоке.

Вложенная процедура?! Как же вы её ухитрились запустить в отдельной нити?! Компилятор не даёт создавать указатели на такие процедуры, чтобы их нельзя было запускать вне той процедуры, в которой они описаны.


06-06-2005 12:48
Возможно, мы друг друга немного не поняли.
Я сделал класс, задача которого - PortMapper.
Естественно, каждому клиенту выделяется отдельный поток. Мой вопрос состоит в том, почему поток, создаваемый методом класса, не может обращаться к полям класса? Одна деталь: внутри метода описана процедура, которую сам метод и запускает в потоке.


06-06-2005 08:18
сообщение от автора материала
Насколько я знаю, метод Synchronize вызывается при обращении к чему-либо, относящемуся к VCL. Но ведь тип объект и класс сами по себе находится не в VCL.

Synchronize - это передача выполнения
процедуры в главную нить. Будет ли эта процедура связана с VCL или нет - не имеет значения. Неглавная нить передаёт сообщение главной (указатель на метод передаётся через параметры сообщения) и приостанавливает свою работу до тех пор, пока сообщение не будет обработано. Главная нить при извлечении из очереди этого сообщения выполняет соответствующую процедуру. Вот и всё. Я предлагал действовать по аналогии: когда неглавная нить фиксирует событие FD_Close, она кидает сообщение главной нити (вашем случае, возможно, даже не понадобится ожидание обработки сообщения - достаточно будет вызвать PostMessage и продолжить работу). А форма должна содержать обработчик этого сообщения и при его получении обновлять требуемые поля. Это можно сделать, даже если форма сделана без использования VCL.

NameLen:=SizeOf(NameLen); Аминь.

Опечатка. Конечно же, SizeOf(TSockAddr).


05-06-2005 12:24
Параметр NameLen содержит длину структуры, описывающей адрес, и должен быть равен SizeOf(NameLen).

NameLen:=SizeOf(NameLen); Аминь.


04-06-2005 14:04
Цитирую:
************
Возможно ли обрашаться к полям напрямую?

А Synchronize не подойдёт?
************

Насколько я знаю, метод Synchronize вызывается при обращении к чему-либо, относящемуся к VCL. Но ведь тип объект и класс сами по себе находится не в VCL.

Проясните, пожалуйста, ситуацию.


03-06-2005 07:46
В MS Knowledge Base очень не советуют использовать

IOCtlSocket

с параметром

FIONRead

. Объясняется это тем, что в момент вызова

IOCtlSocket

буфер приема блокируется, и если в этот момент поступит новая порция данных, то она будет потеряна.
MS советует при срабатывании

select

'a просто звать

recv

до тех пор, пока не будет прочитано 0 байт.

Так же в статье нужно обязательно выделить *большими буквами* те места, в которых говорится, что отправка порции данных через

send

*абсолютно не гарантирует* ее получение за 1 же прием в

recv

.
Это вовсе не значит, что данные теряются по дороге или меняются местами внутри пакета - все приходит точно в том же виде, в каком было отправлено. Просто пакет может быть разбит на части в произвольных местах или быть "склеенным" со следующим(и).

Люди часто жалуются на "загадочное" поведение приложения, не приняв во внимание этот важнейший момент. Все может замечательно (или почти замечательно) работать на локалке, а в реальном мире начинают происходить "необъяснимые" вещи.


27-05-2005 08:49
сообщение от автора материала
Nobodyx:

Если клиент может не успеть обработать данные, то ваш метод вполне подходит, только 1 кб - это слишком мало. Пересылайте хотя бы несколько десятков килобайт за один раз.


23-05-2005 13:07
Что касается передачи файла, то неотвеченным я сочел следующий фрагмент-дополнение к вопросу:

В таком случае, при передаче через ТСP возможна такая проблема:

Сервер будет отсылать данные без остановки, а клиент не успеет их вовремя обработать. Входящий буфер сокета клиента не бесконечный, может произойти сбой передачи файла.


23-05-2005 01:05
сообщение от автора материала
Можно как-то оптимизировать процесс передачи файла?

На этот вопрос я уже ответил - внимательнее читайте моё сообщение от 09-05-2005 02:53

Проблема в том, что о событии FD_CLOSE клиент узнает не сразу, в только при WaitFor..., которое будет вызвано только определенными действиями пользователя.

И на этот вопрос я уже ответил - либо используйте одну нить и асинхронный сокет с сообщениями, а не событиями, либо в отдельной нити, которая делает WaitFor, предусмотрите передачу сообщения главной нити (как это делает Synchronize). Чем вам эти варианты не нравятся?


22-05-2005 08:10
Обращаю Ваше внимание на то, что 2 вопроса остались без ответа:

1)При передаче файла по сети, я использовал такой алгоритм: сервер шлет определенное количество данных( например, 1 кб). Клиент, приняв их, шлет уведомление, что принял данные. И так до конца передачи файла. Уведомление шлётся в целях того, чтоб знать, что клиент успел обработать данные.

Можно как-то оптимизировать процесс передачи файла?

2)Я выделяю для каждого асинхронного сокета новую нить, когда дело касается сервера. В клиенте я использую всего лишь 1 сокет.
Проблема в том, что о событии FD_CLOSE клиент узнает не сразу, в только при WaitFor..., которое будет вызвано только определенными действиями пользователя.
Я имел в виду вариант, когда выделяется 1 поток только на обработку событий сокета, в котором будет отслеживаться FD_CLOSE.


20-05-2005 12:06
сообщение от автора материала
Ну так можно посмотреть исходный код Synchronize и сделать по аналогии. Там всё просто.


20-05-2005 11:55
Потоки на АПИ...


20-05-2005 01:07
сообщение от автора материала
Возможно ли обрашаться к полям напрямую?

А Synchronize не подойдёт?


19-05-2005 13:34
Я не совсем точно выразился. Я выделяю для каждого асинхронного сокета новую нить, когда дело касается сервера. В клиенте я использую всего лишь 1 сокет.
Проблема в том, что о событии FD_CLOSE клиент узнает не сразу, в только при WaitFor..., которое будет вызвано только определенными действиями пользователя.
Я имел в виду вариант, когда выделяется 1 поток только на обработку событий сокета, в котором будет отслеживаться FD_CLOSE.

Быть может вопрос немного не по теме...
Я сделал на асинхр. сокетах объект наподобе входящего в Indy IdMappedPortTCP. Когда новому клиенту выделяется отдельный поток, этот самый поток не может обращаться к полям объекта, в итоге приходится извращаться  - сохдавать динамическую переменную, запихивать туда данные из полей и прередавать в поток указатель.
Возможно ли обрашаться к полям напрямую?


15-05-2005 03:52
сообщение от автора материала
Прошу прощения за задержку с ответами, закрутился и забыл, что тут заданы вопросы.

Nobodyx:

Я сделал удаленную коммандную строку, просто указывая дескриптор сокета как как хэндл стандартного ввода и вывода при создании процесса CMD.EXE. (мктод гораздо проще, чем через пайпы)
Хотелось бы узнать, как оно работает.


А структуру каких внутренних объектов Windows вы знаете? Документируются только их внешние свойства, а не структура. Не знаю, документировано ли где-то, что в сокет можно перенаправлять вывод с консоли, или же это побочный эффект, но вот то, что внутренняя структура его не документирована, уверен почти на 100%.

Поясняю ситуацию: если происходит FD_CLOSE, программа узнает об этот только при WaitFor...
Программа является клиентом, так что она делает WaitFor... только в те моменты, когда пользователь
очуществляет какое-то действие.
Можно ли узнать об FD_CLOSE "как только,так сразу". Знаю, что можно создать отдельный поток и в нем непрерывно проверять уведомления от сокета, но мне кажется этот вариант немного через одно место.


Последний вариант - как раз через то место, через которое нужно :)

WaitFor... и асинхронные сокеты с событиями логичнее всего употреблять в отдельных нитях, которые не делают ничего, кроме работы с этим сокетом. А если вы используете нить, обрабатывающую ввод пользователя и имеющую, соответственно, петлю сообщений, вам логичнее использовать сокеты с сообщениями, т.е. WSAAsyncSelect, а не WSAEventSelect. Тогда при закрытии сокета вы сразу получите сообщение. А проверять в ответ на действия пользователя, пришло ли что-то на сокет, можно, используя select, IOCtlSocket или Recv (сокет-то будет неблокирующий).

Допустим, cерверу отправили строку "disconnect"(через ТСР).
Возможна такая ситуация, что первый раз вызвав recv, сервер прочитает "dis", -отбросит как неизвестную комманду, во второй вызов recv прочитает "connect" и расценит это как комманду?


Теоретически - возможно, хотя на практике при таком размере пакета вероятность разбивки его на две части будет пренебрежимо мала. Скорее, две посланные подряд команды могут склеиться. Но вообще TCP в этом смысле не очень удобный протокол. Здесь приходится договариваться, что каждая команда имеет признак конца (например, #0). Обработчик FD_READ, если он не встречает признак конца команды, должен сохранить данные в буфере и присоединить к ним следующую посылку, и так до тех пор, пока не встретится #0. При этом надо учитывать, что #0 может встретиться и в середине пакета - это значит, что вторая половина пакета уже относится к другой команде.

Как написано в статье, можно включать в каждое послание заголовок фиксированной длины N, в котором указывать размер отсылаемых данных.
Но также стоит учитывать, что сервер, прочитав меньше чем N байт, должен знать, что надо считать оставшуюся часть заголовка?
Или есть лучший выход из ситуации?


В принципе, да - сервер должен вызывать recv до тех пор, пока суммарный объём полученных данных не достигнет размера заголовка. Но, повторюсь, при небольших размерах заголовка вероятность деления его на части исчезающе мала (если, конечно, на другой стороне его отправляют целиком, а не по частям).

Antrax:

Возможно ли выставить таймаут операций Send и Recv при работе с блокирующими сокетами?

Нет, понятия таймаута для этих операций не существует. В блокирующем режиме они завершаются только при успешном выполнении операции или при фатальной ошибке. Выходом из положения является использование функции Select - с её помощью выполнить ожидание активности на сокете с таймаутом и, если ожидание завершилось успешно, вызывать Recv или Send.


14-05-2005 15:46
Вопрос про соединение (if WaitForSingleObject(SEvent, TimeOut)   =WAIT_OBJECT_0 then...) отпадаетв силу моей глупой ошибки.


10-05-2005 02:18
Возможно ли выставить таймаут операций Send и Recv при работе с блокирующими сокетами?


09-05-2005 05:19
*****Цитата:(не могу норм. процитировать, java script глюит)
Какова внутренняя структура сокета, что возможно передавать дескриптор сокета в качестве дескриптора файла в функции ReadFile и WriteFile?

Не думаю, что это вообще документировано. Вам действительно это надо знать?
*****
Я сделал удаленную коммандную строку, просто указывая дескриптор сокета как как хэндл стандартного ввода и вывода при создании процесса CMD.EXE. (мктод гораздо проще, чем через пайпы)
Хотелось бы узнать, как оно работает.
==============================
*****Цитата:
Нет ли более оптимального алгоритма проверки разрыва связи в асинхронных сокетах(на событиях), чем при каждом вызове WaitFor... рассматривать случай FD_CLOSE?

Мне иной способ неизвестен. И не понимаю, почему этот вам кажется неоптимальным.
*****

Поясняю ситуацию: если происходит FD_CLOSE, программа узнает об этот только при WaitFor...
Программа является клиентом, так что она делает WaitFor... только в те моменты, когда пользователь
очуществляет какое-то действие.
Можно ли узнать об FD_CLOSE "как только,так сразу". Знаю, что можно создать отдельный поток и в нем непрерывно проверять уведомления от сокета, но мне кажется этот вариант немного через одно место.
==============================
******Цитата:
Алгоритм Нагля, который используется для определения размера куска, передаваемого по сети, может разбивать данные на несколько порций. Размер порции может зависеть, например, от нагрузки на сеть.
******
Допустим, cерверу отправили строку "disconnect"(через ТСР).
Возможна такая ситуация, что первый раз вызвав recv, сервер прочитает "dis", -отбросит как неизвестную комманду, во второй вызов recv прочитает "connect" и расценит это как комманду?

Т.е. модель клиента и сервера, когда сервер:
ждет FD_READ, делает recv, рапознает пришедшую комманду, выполняет, отсылает данные клиенту результат, не годится в реальной жизни?

Как написано в статье, можно включать в каждое послание заголовок фиксированной длины N, в котором указывать размер отсылаемых данных.
Но также стоит учитывать, что сервер, прочитав меньше чем N байт, должен знать, что надо считать оставшуюся часть заголовка?
Или есть лучший выход из ситуации?
==============================
Еще 1 вопрос:
Попытку соединения я осуществлял так:

  SEvent:=WSACreateEvent;
  WSAEventSelect(Sock,SEvent, FD_CONNECT);
  connect(sock,@addr,sizeof(addr));
  if WaitForSingleObject(SEvent, TimeOut)   =WAIT_OBJECT_0 then...

Проблема в том, что если приходит смгнал, что данный порт недоступен, то WaitForSingleObject продолжает ждать, ожидая FD_CONNECT в течении TimeOut. Как можно учесть приход сигнала, что порт недоступен, во избежание лишнего ожидания?
==============================

Извините, что так навалился со своими вопросами, но больше негде спросить, чтоб получить толковый ответ :(


09-05-2005 04:38
Извините, что не могу процитировать текст, java script глючит.

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

В таком случае, при передаче через ТСP возможна такая проблема:

Сервер будет отсылать данные без остановки, а клиент не успеет их вовремя обработать. Буфер сокета не бесконечный, может произойти сбой передачи файла.


09-05-2005 02:53
сообщение от автора материала
Какова внутренняя структура сокета, что возможно передавать дескриптор сокета в качестве ескриптора файла в функции ReadFile и WriteFile?

Не думаю, что это вообще документировано. Вам действительно это надо знать?

При передаче файла по сети, я использовал такой алгоритм: сервер шлет определенное количество данных( например, 1 кб). Клиент, приняв их, шлет уведомление, что принял данные. И так до конца передачи файла. Уведомление шлётся в целях того, чтоб знать, что клиент успел обработать данные.

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

С чем связано то, что данные(меньше в 2 раза объёма исходящего буфера), отправленные во время одного вызова Send (протокол TCP) при приеме прочитаться только после нескольких вызовов Recv (входящий буфер пуст)?

Алгоритм Нагля, который используется для определения размера куска, передаваемого по сети, может разбивать данные на несколько порций. Размер порции может зависеть, например, от нагрузки на сеть.

Нет ли более оптимального алгоритма проверки разрыва связи в асинхронных сокетах(на событиях), чем при каждом вызове WaitFor... рассматривать случай FD_CLOSE?

Мне иной способ неизвестен. И не понимаю, почему этот вам кажется неоптимальным.


08-05-2005 15:24
Забыл спросить:

3)С чем связано то, что данные(меньше в 2 раза объёма исходящего буфера), отправленные во время одного вызова Send (протокол TCP) при приеме прочитаться только после нескольких вызовов Recv (входящий буфер пуст)?

4)Нет ли более оптимального алгоритма проверки разрыва связи в асинхронных сокетах(на событиях), чем при каждом вызове WaitFor... рассматривать случай FD_CLOSE?


08-05-2005 15:14
Статья очень понравилось, все очень доходчиво изложено. Это единственная достойная статья, которую мне смог предложить google.

Хотелось бы уяснить для себя несколько вопросов:

1)Какова внутренняя структура сокета, что возможно передавать дескриптор сокета в качестве ескриптора файла в функции ReadFile и WriteFile?

2)При передаче файла по сети, я использовал такой алгоритм: сервер шлет определенное количество данных( например, 1 кб). Клиент, приняв их, шлет уведомление, что принял данные. И так до конца передачи файла. Уведомление шлётся в целях того, чтоб знать, что клиент успел обработать данные.

Можно как-то оптимизировать процесс передачи файла?


20-04-2005 03:12
сообщение от автора материала
heilong:

Насчёт прерывания ожидания select пока ничего не придумывается. Думаю, если бы такие проблемы легко и красиво решались, никто бы не стал возиться с придумыванием асинхронных сокетов. Наверное, создание дополнительного сокета - самое целесообразное в рамках синхронных сокетов решение.


14-04-2005 06:36
Опять же к тебе Антон по поводу блокированного режима. Есть простая задача прервать для сервера (1 сокет)

select(0, @FDset, nil, nil, nil)



Прервать нужно для того чтобы завершить работу приложения(сделать проверку на завершение).
Выход через WSASetBlockingHook мягко говоря безсмысленный, хук вызывается офигенно часто, и просто теряет смысл применять вышеописанный select проще в цикле вызывать с таймаутом.

Однако использовать асинхронные сокеты (все переписывать) не хочется, и я нашел только одно решение:
Создать еще один сокет с типом UDP


FUnbSocket := winsock.socket(PF_INET, winsock.SOCK_DGRAM, IPProto_IP);
...
winsock.bind(FUnbSocket, FUnbSockAddrIn, len);
winsock.getsockname(FUnbSocket, FUnbSockAddrin, len);
winsock.connect(FUnbSocket, FUnbSockAddrIn, len);



Тоесть грубо говоря сделать сокет с фильтром "сам на себя". После чего к множеству в вышеописанном select добавить еще и этот вновьсозданный сокет.

В таком случае отправка любого сообщения "сам себе":

winsock.sendto(FUnbSocket, Buffer, BufferLen, 0, FunbSockAddrIn,  len)



приведет к прерыванию работы select, и все что нужно так это после этого отфильтровать результат.

Может есть какие-нибудь другие решения, и чем плохо это(не беря во внимание затраты в ресурсах на новый сокет, и захваченный порт)?


12-04-2005 03:55
сообщение от автора материала
heilong:

Про функции, связанные с работой петли сообщений во время блокирующих вызовов см. вторую часть статьи - о них там написано. А RDP, как я понял, это какое-то нестандартное расширение TCP/IP. Не уверен, что оно вообще поддерживается стандартным провайдером TCP/IP для Windows.


12-04-2005 03:46
по поводу WSACancelBlockingCall цитирую MSDN:

The WSACancelBlockingCall function has been removed in compliance with the Windows Sockets 2 specification, revision 2.2.0.
The function is not exported directly by WS2_32.DLL and Windows Sockets 2 applications should not use this function. Windows Sockets 1.1 applications that call this function are still supported through the WINSOCK.DLL and WSOCK32.DLL.

Тоесть функция пока поддерживается любой(поддерживающей Sockets 1.1) версией Windows.

Также жалко Антон что ты не осветил работу след. функций для блокирующего режима:
WSACancelBlockingCall()
WSAIsBlocking()
WSASetBlockingHook()
WSAUnhookBlockingHook()

И собственно вопрос, упоминаемый в статье RDP - можно немного поподробнее в отличии его от UDP, не на уровне пакетов, а на уровне сокетов. Складывается впечатление что с ним надо работать как с TCP, и единственное его отличие в создании сокета.


02-10-2004 01:01
Статья интересная.И хорошо изложена.Но мне кажеться, что не все еще сказано.Помойму приведение примера в дельфи на работу с библеотекой winsocks просто необходима.


22-09-2004 18:04
сообщение от автора материала
Вобщем, вопрос еще такой: а размер входного/выходного буфера сокета чему равен?

8192 байта, но при необходимости туда может влезть гораздо больше. Читайте статью внимательнее - в разделе "Параметры сокета" это подробно описано.


22-09-2004 16:48
Антон, а, может быть, здесь просто имеет место переполнение выходного буфера сокета?
"Глюки" перестали наблюдаться, когда размер отсылаемых данных стал < 16kb.
Кроме того, при разбиении 48kb данных на 3 части и последовательной отсылке оных, так же наблюдалось нечто непонятное. Однако, после установки некоторой задержки по времени между последовательными посылками все нормализовалось.
Вобщем, вопрос еще такой: а размер входного/выходного буфера сокета чему равен?
С уважением,
Василий.


20-09-2004 12:32
сообщение от автора материала
Василию:

На данный момент я ещё не изучил, как работает SendBuf и ReceiveBuf, поэтому ответить вам не могу. Рекомендую задать этот вопрос на Круглом столе.


14-09-2004 17:21
Прошу прощения, возникла "опечатка":

написано:"величина, возвращаемая SendBuf'ом после каждой посылки от клиента "плавает": "

на самом деле:"величина, возвращаемая SendBuf'ом после каждой посылки от сервера "плавает": "


14-09-2004 16:52
Здравствуйте, Антон!
Спасибо за ответ на вопрос о вышибании "мертвых" соединений. Проблема именно так и решилась.

Возникла, правда, еще одна проблема при попытке пересылки данных относительно большого объема:
приложение-сервер периодически пересылает (раз в 0.5 сек) с помощью TServerSocket данные из буфера размером 48024 байта. Эту же величину (48024) выдает и SendBuf.
На клиентской стороне (TCLientSocket) данные считываются в обработчике OnRead.  Сокеты работают в неблокирующем режиме.
Так вот, при получении информации клиентом возникают чудеса: ReciveBuf возвращает только 13096. Ради интереса, с помощью IOCTLSocket (команда FIONRеad) посмотрел размер буфера клиентского сокета: перед вызовом ReciveBuf - 8192(?!), после - 0. При более внимательном вглядывании, оказалось, что сразу после подключения, величина, возвращаемая SendBuf'ом после каждой посылки от клиента "плавает": 10972, 10736, 6724 (в этот момент, размер буфера от IOCTLSocket, также вдруг становится равным этой величине), а затем "устаканивается" на значении 13096.
Вот, теперь, и озадачен я классическими вопросами: кто виноват, и что делать?
:)


07-09-2004 18:54
сообщение от автора материала
Юрий, организация буфера - это отдельный вопрос, который требует знания массивов, строк, указателей... Я могу навскидку привести не меньше десяти способов организовать буфер (а если дать мне время подумать - то ещё больше), и каждый из них имеет право на существование, у каждого есть своя область применения. Для человека, который знает всё это, мой пример будет бесполезен, потому что в зависимости от ситуации он всё равно выберет свой способ. А для человека, который этого не знает, пример вообще будет вреден, потому что вынудит его использовать один и тот же способ во всех ситуациях, в том числе и в тех, когда надо придумывать что-то другое. Знаете что, Юрий, вы лучше напишите на Круглый стол, что вы хотите сделать и что у вас не получается, и мы вместе решим проблему.


07-09-2004 17:54
Очень полезная статья! Хотел сделать примерчик, использующий стандартные сокеты, но ничего не получилось. Что только не перепробывал. Не ругается, но и не работает.  Хотел элементарно послать и получить строку. Но непонятно, что есть буфер. И как из него что-нибудь прочитать или положить (например ту же самую строку)? Пример сервера и клиента в статье на самом интересном месте прерывается на функциях Recv и Send.
Было бы неплохо привести самый простой, но работающий пример. Интересно поработать именно непосредственно с сокетами ибо с использованием компонент все работает замечательно.


14-08-2004 08:53
сообщение от автора материала
Как прервать выполнение функции select у блокирующего сокета из другого потока? И возможно ли это?

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


13-08-2004 16:07
Спасибо за статью! Очень полезно.
Может, это не по теме, но очень хочется спросить.
Как прервать выполнение функции select у блокирующего сокета из другого потока? И возможно ли это?

Вопрос связан с тем, что я программирую по технологии Midas с применением SocketConnection, и мне хотелось бы получить возможность прерывания долго выполняющегося запроса. В модуле SConnect.pas есть метод function TSocketTransport.Receive, с котором сокет ждет возврата после выполнения select(). Допустим, в одном потоке select() ждет возврата, в то время как из другого потока пользователь наживает на кнопку, и select() обрывается. Как бы это сделать? Долго этот вопрос меня бепокоит.

В MSDN не нашел подходящей функции.


12-08-2004 16:59
сообщение от автора материала
Уважаемый Антон!
Статья интересна теоретически. Но, программируя на Delphi, нужно ли связываться с сокетами на таком уровне? Ведь есть же ClientSocket/ServerSocket, TCPClient/TCPServer, UDPSocket, IdTCPClient/IdTCPServer для TCP в Delphi7. Скажите пожалуйста, планируете ли Вы подробно, с примерами, для синхронного и асинхронного режима описывать вышеперечисленные компоненты? Спасибо


Планирую, о чём и написано в самом начале статьи. А знать такие низкоуровневые вещи всё-таки надо, иначе работа компонентов не будет понятна.


12-08-2004 15:51
Уважаемый Антон!
Статья интересна теоретически. Но, программируя на Delphi, нужно ли связываться с сокетами на таком уровне? Ведь есть же ClientSocket/ServerSocket, TCPClient/TCPServer, UDPSocket, IdTCPClient/IdTCPServer для TCP в Delphi7. Скажите пожалуйста, планируете ли Вы подробно, с примерами, для синхронного и асинхронного режима описывать вышеперечисленные компоненты? Спасибо


07-08-2004 16:15
сообщение от автора материала
Заранее прошу прощения, за, быть может, ламерский вопрос: а как работает механизм возврата значения функции для работы с сокетом в неблокирующем режиме?

Да так же, как и в блокирующем: кладёт данные в буфер сокета и тут же завершается. А данные отправляются потом в фоновом режиме. Разница будет только в том случае, если в буфере нет места: в блокирующем режиме Send будет ждать, пока оно появится, а в неблокирующем вернёт WSAEWouldBlock.

Конечно, подобная ситуация отнюдь не выглядит неразрешимой, но может есть некий проверенный подход для более быстрого обнаружения и выбивания "мертвых" сокетов?

Можно сделать неблокирующий сокет и таймаут: если клиент слишком долго ничего не присылает, связь считается потерянной и сервер закрывает сокет. А клиент тогда должен заботиться, чтобы с определённой периодичностью что-нибудь серверу отправлять.


06-08-2004 14:36
С большим удовольствием прочитал данный материал!
С нетерпением жду продолжения.

Хотелось бы уточнить один момент:
"Функция Send для неблокирующего сокета также имеет некоторые специфические черты поведения.
... В этом случае функция Send копирует в выходной буфер такой объём данных, для которого хватает места, и возвращает значение, равное этому объёму ..."


Заранее прошу прощения, за, быть может, ламерский вопрос: а как работает механизм возврата значения функции для работы с сокетом в неблокирующем режиме? Например, в коде есть строка:

k:=Send(...);
...
И как все будет происходить? Возвращенное значение от функции появится в k "через некоторое время"?

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

С уважением и наилучшими пожеланиями!


23-07-2004 10:04
Спасибо за собранную и переработанную информацию.

А будет ли еще (очень скромно надеюсь) описание того, как можно "слушать" http-соединение с помошью сокетов? А то все примерв на С...


04-07-2004 08:54
Здорово! А то вроде знаешь... Где-то, по немногу а в одном месте и так доступно изложено!!! Большое Спасибо за то что собрал все в стек :)


19-06-2004 08:54
сообщение от автора материала
Для DRON:

Да, меня уже убедили, что здесь я ошибся. В тексте есть и более мелкие неточности. Сейчас я собираю материал, а потом разом исправлю всё.


19-06-2004 01:39
По поводу:
С серверами всё несколько сложнее. Система привязывает сокет к адресу, когда сокет TCP-сервера переходит в режим ожидания подключения
Только что провёл эксперимент: взял сервер где приёмный сокет биндится как ADDR_ANY и подключился к нему одновременно с четырёх сеток (Ethernet, WiFi, WMNet и Loop с разными IP и масками). Всё прекрасно работает, клиенты видят сервер под разными IP (в зависимости от сетки). Так что для самого Listen-сокета привязка, судя по всему, не выполняется, привязываются только возвращённые accept-ом сокеты.


17-06-2004 18:18

только нужно подправить

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

Значение, возвращаемое функцией RecvFrom, равно длине прочитанной дейтаграммы.
Это значение может быть равно нулю, т.к. UDP позволяет отправлять дейтаграммы нулевой длины (для этого при вызове SendTo надо задать параметр Len равным нулю). Если обнаружена какая-то ошибка, возвращается значение Socket_Error.



17-06-2004 18:12
гениально:)


17-06-2004 11:35
Отлично, но надо разделить на части


17-06-2004 11:20
Привет Всем.

Нашел в интернете модули для работы с сокетами...
посмотри может понадобятся...

Synapse
The synchronyous socket library.

Synapse homesite is at http://www.ararat.cz/synapse/

С уважением Иван.


17-06-2004 10:31
сообщение от автора материала
Возможно, было бы резонно разделить ее на две части.

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

Кстати, литературы по данному вопросу с таким уровнем изложения практически нет.

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


16-06-2004 18:55
Отличная работа, Антон!
Достойно хорошего печатного издания. Кстати, литературы по данному вопросу с таким уровнем изложения практически нет.


16-06-2004 05:55
иб есьм зер гуд.
как обобщение и приведение в систему.


16-06-2004 00:58
Огромное спасибо! Много интересного для себя узнал. Однако, статья слишком огромна. За один присест не прочитать. Я осилил только половину. Возможно, было бы резонно разделить ее на две части.


Добавьте свое 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» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

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