Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2011.12.04;
Скачать: [xml.tar.bz2];

Вниз

Работа с сокетами (теория)   Найти похожие ветки 

 
GanibalLector ©   (2009-07-02 16:51) [0]

Добрый день!

Имеется следующая задача. Есть девайсы, к ним подключены модемы.
В данный момент я дозваниваюсь к ним и обмениваюсь данными(через TAPI).
Все хорошо, все работает. Решили удешевить стоимость обмена , увеличить скорость обмена и перейти на GPRS.
Модемы прошили ( на работу с GPRS ), проверил все работает.

В связи с этим пару вопросов.

1) начитался я А.Б.Григорьева и не пойму. а какие сокеты выбрать ?
Блокирующие/не блокирующие (асинхронные на сообщениях,на событиях и т.д.)

Впервые работаю с сокетами.

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

Т.е. в моем коде весь обмен сводится к одной ф-ции,  в которой есть ReadFile и WriteFile(для работы с RS232).
Вот ,например  :

procedure Request(Busy,NoWrite:Boolean; HPort: THandle;
 AddrPC, Addr, Cmd: Byte; const Data: string;
 out Status: TStatusRec; out Reply: string); overload;
var
...
begin
 if not Busy then
  Num := Byte(InterlockedIncrement(ncmd)) else
  Num:=  Byte(ncmd);
 Reply := "";
 Databuffer := FormatBuffer(AddrPC, Addr, Num, Cmd, Data);
 evOverlapped := CreateEvent(nil, True, True, nil);
 try
   if not WinCheck(SetCommMask(HPort, EV_RXCHAR or EV_ERR), Status) then Exit;

   if not NoWrite then
   begin
     ZeroMemory(@Overlapped, SizeOf(Overlapped));
     Overlapped.hEvent := evOverlapped;
     if not WinCheckOvr(WriteFile(HPort, Databuffer[1], Length(Databuffer),
       Transferred, @Overlapped), Status) then Exit;
     if not Wait(WriteTimeout, evOverlapped, Status) then Exit;
     if not WinCheck(GetOverlappedResult(HPort, Overlapped,
       Transferred, False), Status) then Exit;
   end;

   ...

 finally
   CloseHandle(evOverlapped);
 end;
end;


Т.е. я открываю порт и передаю в эту ф-цию хендл. А сама ф-ция что-то передает/принимает.

Что я хочу. Создам  сервер. Подключу клиента. В эту ф-цию передам сокет подключившегося клиента и изменю ReadFile|WriteFile на
на Recv , Send. Ну...это условно. Я понимаю, что этим конечно дело не закончится.

Правильный ли ход моих мыслей ?

Заранее спасибо !!!


 
GanibalLector ©   (2009-07-02 16:54) [1]

Небольшое уточнение.

Удаленные клиенты (в моем случаи) ничего сами по себе данные не передают. Т.е. я обязан выслать пакет и только после этого клиент ответит.


 
Сергей М. ©   (2009-07-02 17:09) [2]


> В эту ф-цию передам сокет подключившегося клиента и изменю
> ReadFile|WriteFile на
> на Recv , Send


Вовсе не обязательно  изменять.
ReadFile|WriteFile успешно работают и с сокетным транспортом, т.е. в эти ф-ции допустимо передавать параметром хэндл сокета.


> понимаю, что этим конечно дело не закончится


Это да.
Поработать напильником придется изрядно)


> не пойму. а какие сокеты выбрать ?


Да любые)
Все равно напильником работать придется.

Блокирующий режим проще в алгоритмической реализации сокетного транспорта, но он блокирует кодовый поток на время выполнения ф-ций сокетного ввода/вывода.

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


 
GanibalLector ©   (2009-07-02 17:23) [3]


> Вовсе не обязательно  изменять.ReadFile|WriteFile успешно
> работают и с сокетным транспортом, т.е. в эти ф-ции допустимо
> передавать параметром хэндл сокета.


Да, но тот же А.Б.Григорьев говорит следующее : специальных ф-ций для перекрытого ввода-вывода в WinSock1 не было, требовались ReadFile и WriteFile. В WinSock2 появилась полноценная поддержка перекрытого ввода-вывода для всех версий Windows...Здесь мы  будем рассматривать перекрытый ввод-вывод только в спецификации WinSock2, т.к. старый вариант из-за своих ограничений уже не имеет практического смысла

Вот что пугает !


 
Сергей М. ©   (2009-07-02 20:05) [4]

Страхи свои обрати к Антону, ибо жив и уважаем)


 
Сергей М. ©   (2009-07-02 20:08) [5]


> GanibalLector


Впрочем, это к слову о минимальной переделке твоего кода, а не переписи его с нуля


 
Вариант   (2009-07-03 07:20) [6]


> GanibalLector ©   (02.07.09 16:51)


Мое мнение и не более:

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


 
Сергей М. ©   (2009-07-03 08:14) [7]


> Вариант   (03.07.09 07:20) [6]


> В этом случае  ReadFile и WriteFile правда прийдется поменять
> на recv и send.


С чего бы вдруг ?


 
Вариант   (2009-07-03 09:34) [8]


> Сергей М. ©   (03.07.09 08:14) [7]


С собственного опыта.

В свое время, прочитал в MSDN для WriteFile

> hFile
> [in] Handle to the file. The file handle must have been
> created with the GENERIC_WRITE access right. For more information,
>  see File Security and Access Rights.
> For asynchronous write operations, hFile can be any
> handle opened with the FILE_FLAG_OVERLAPPED flag by the
> CreateFile function, or a socket handle returned by the
> socket or accept function.


Не понравилась мне выноска (жирным выделил) в асинхронные  операции сокетов.  Проверил кодом для блокирующих сокетов (сокет получен функцией accept) для Winsock 1.1 и/или Winsock 2.2, не работает WriteFile, возвращает false.  GetLastError и WsaGetLastError вернули ошибку "Параметр задан не верно". В качестве handle для WriteFile  пробовал передавать как сам сокет, так и handle полученный DuplicateHandle. А вот send работает с тем же сокетом или дублированным handle.

Код для WriteFile


> Res := WriteFile(Soc, s[1], j, cardinal(j), 0);
>                   if not Res then
>                     begin
>                       s1 := SysErrorMessage(WSAGetLastError);// GetlastError тоже
>                    
>                     end;


Где Soc -сокет полученный accept, s[1] -строка, j - длина строки, Res - bool

ПРоверялось в Windows XP на D6.

Я допускаю что мог ошибиться или чего-то еще не знать. Может ты делал такие операции с блокирующим сокетом? Если есть, то может покажешь код, где для блокирующих сокетов WriteFile работает в Winsock 1.1 или Winsock 2.2?
Было бы интересно посмотреть.


 
Сергей М. ©   (2009-07-03 10:22) [9]


> GetLastError и WsaGetLastError вернули ошибку "Параметр
> задан не верно"


А с чего ты взял, что ошибка относится к 1-му параметру ?

Она отнюдь не к первому относится, а к последнему : ты передал туда 0 (nil), а следовало передать указатель на структуру TOverlapped, ибо overlapped-режим ввода/вывода в этом случае обязателен


 
Вариант   (2009-07-03 10:36) [10]


> Сергей М. ©   (03.07.09 10:22) [9]

Согласен, возможно и так.

Я использовал просто блокирующий сокет не в overlapped режиме.
Поэтому в этом случае WriteFile работать не будет, собственно я имел ввиду это.  Когда писал [6]


 
Сергей М. ©   (2009-07-03 10:48) [11]


> Вариант   (03.07.09 10:36) [10]


Так что будет оно работать, куда оно денется)

Но, конечно же, применять ли файлопоточные ф-ции ввода-вывода или пользовать [WSA]Send/Recv - этот выбор должен делаться исходя из конкретной ситуации и условий.


 
Вариант   (2009-07-03 10:53) [12]


> Сергей М. ©   (03.07.09 10:48) [11]

Я не утверждал, что оно не будет работать вообще


 
GanibalLector ©   (2009-07-03 14:11) [13]

2 Вариант

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


Да...пока так и сделал. Что-то даже начало работать(делал с recv и send ).
Но !!! Клиентов много. Каждому клиенту отдать поток не могу. Тут прийдется или пул делать или выбирать неблокирующие. Даже не знаю..


 
Вариант   (2009-07-03 15:09) [14]


> GanibalLector ©   (03.07.09 14:11) [13]

Согласен.
Если количество одновременно работающих клиентов велико ( то есть у тебя сервер, и ты работаешь с клиентами) или может вырасти в дальнейшем, то блокирующий не overlapped сокет не самое лучшее решение. Причем не лучшее решение именно из-за числа одновременно работающих потоков, мне кажется.
Посмотри книгу
"Программирование в сетях Microsoft Windows" Э.Джонс, Д.Оланд. Довольно подробно рассмотрены разные варианты работы с сокетами.


 
GanibalLector ©   (2009-07-03 17:25) [15]

Попробовал писать через WriteFile. Работает. Ниже код.
Не понятно с чтением. Для порта я флаги ставил...а тут я так понимаю они не нужны теперь.

function WinCheck(Val: BOOL;  AllowOvr: Boolean= False): BOOL;
begin
 if not Val then
 begin
   if AllowOvr and (GetLastError = ERROR_IO_PENDING) then
   begin
     Result := True;
     Exit;
   end;
 end;
 Result := Val;
end;

function WinCheckOvr(Val: BOOL): BOOL;
begin
 Result := WinCheck(Val, True);
end;

function Wait(Timeout: DWORD; hData: THandle): Boolean;
 var W:DWORD;
begin
 Result:=False;
 W:=WaitForSingleObject(hData,Timeout);
 case W of
   WAIT_OBJECT_0 : Result:=True;
   WAIT_TIMEOUT  : Result:=False;
 end;
end;

Str:="Hello,World";
evOverlapped := CreateEvent(nil, True, True, nil);
 try
   ZeroMemory(@Overlapped, SizeOf(Overlapped));
   Overlapped.hEvent := evOverlapped;
   //
   if not WinCheckOvr(WriteFile(FSocket,Str[1],Length(Str),J,@Overlapped)) then Exit;
   if not Wait(500,evOverlapped) then Exit;
   if not WinCheck(GetOverlappedResult(FSocket, Overlapped,J, False)) then Exit;
   //
 finally
   CloseHandle(evOverlapped);
 end;


 
GanibalLector ©   (2009-07-03 17:39) [16]


> Не понятно с чтением. Для порта я флаги ставил...а тут я
> так понимаю они не нужны теперь.


И еще. Ранее я использовал ClearCommError чтобы взять кол-во пришедших байт в порт. А сейчас как ? По одному байту что-ли читать ?
Могу конечно IOctlSocket с флагом FIONREAD но уместно ли это ?

Это так...мысли в слух.


 
Polevi ©   (2009-07-03 17:46) [17]

для нагруженных систем лучше Completion Ports использовать, я могу пример дать если интересно


 
GanibalLector ©   (2009-07-03 17:49) [18]

2 Polevi ©   (03.07.09 17:46) [17]

Да, очень.
Сюда , если можно : Talla2kDOGukr.net

И еще вопрос сразу. У меня ситуация такая, что я сперва должен что-то отправить, а потом устройство ответит. А во всех серверах наоборот...они ждут. а потом отвечают.


 
GanibalLector ©   (2009-07-03 18:59) [19]


> И еще. Ранее я использовал ClearCommError чтобы взять кол-
> во пришедших байт в порт. А сейчас как ? По одному байту
> что-ли читать ?


Таки да. По одному все получилось.
Вот...если кому интересно :

evOverlapped := CreateEvent(nil, True, True, nil);
 try
   repeat
     //
     J:=1;
     SetLength(Str, J);
     ZeroMemory(@Overlapped, SizeOf(Overlapped));
     Overlapped.hEvent := evOverlapped;
     if not WinCheckOvr(ReadFile(FSocket, PChar(Str)^, J,J, @Overlapped)) then Break;
     if not Wait(2500, evOverlapped) then Break;
     if not WinCheck(GetOverlappedResult(FSocket, Overlapped,J, False)) then Break;
     //
     LogMessage("принял байт "+Str+" "+IntToHex(Ord(Str[1]),2));
   until False;

 finally
   CloseHandle(evOverlapped);
 end;


Правда один байт теряется. Странно, но разберусь.
Т.е. после коннекта принимаю строку(но ее может и не быть).В общем принимаю или жду 2500мс и иду дальше. Далее спустя какое-то время клиент посылает пакет и первый байт этого пакета я теряю.

Видимо это связано с тем, что я начал чтение одного байта, но оно было прервано .


 
Сергей М. ©   (2009-07-04 15:12) [20]


> во всех серверах наоборот...они ждут. а потом отвечают


Чего ждут-то ? Запроса ? Так и у тебя та же ситуация - ты отправляешь запрос, и устройство на этот запрос отвечает ..

И с чего такая уверенность, что "во всех" ?


> после коннекта принимаю строку(но ее может и не быть)


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


 
GanibalLector ©   (2009-07-05 20:44) [21]


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


Да, все верно. Девайс - нет. Модем - да. При коннекте модем выдает что-то типа "Bridge connect". Вот и получается, что мне приходится ждать около секунды(ждать приветствие модема),а только потом посылать девайсу данные.


> Чего ждут-то ? Запроса ? Так и у тебя та же ситуация - ты
> отправляешь запрос, и устройство на этот запрос отвечает
> ..И с чего такая уверенность, что "во всех" ?


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


В общем, отказался от ReadFile\WriteFile. Использую (блокирующий режим) Send\Recv совместно с select и ioctlsocket.

Т.е. в отдельном потоке ожидаю события через select . Далее вызываю  ioctlsocket, чтобы узнать сколько байт пришло. Ну и читаю или пишу.
Вроде работает. Напряг с кол-вом клиентов (не могу я столько потоков запускать).


 
Сергей М. ©   (2009-07-06 09:02) [22]


> GanibalLector ©   (05.07.09 20:44) [21]


А ты уверен, что модем отныне всегда будет работать в режиме моста ?
Ситуация с переводом модема в режим роутера исключена ?


> Напряг с кол-вом клиентов (не могу я столько потоков запускать)


А и не надо. Здесь поможет организация диспетчеризуемого пула потоков.


 
GanibalLector ©   (2009-07-06 10:45) [23]


> Ситуация с переводом модема в режим роутера исключена ?


А разве можно модем перевести в режим роутера ? И что это, кстати, даст ?
Я не большой знаток сетевых технологий...поэтому и интересуюсь


 
Сергей М. ©   (2009-07-06 12:23) [24]


> разве можно модем перевести в режим роутера ?


Если он поддерживает такую функциональность, то почему нет ?
Например, многие dsl-модемы даже бюджетного класса могут работать и в режиме моста и в режиме маршрутизатора.
За GPRS-модемы не скажу, попросту никогда не интересовался за ненадобностью, полюбопытствуй сам.


> что это, кстати, даст ?


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


 
Похмелкин   (2009-07-06 20:51) [25]


> Напряг с кол-вом клиентов (не могу я столько потоков запускать).

Посмотрите это
http://www.torry.net/vcl/internet/sockets/HPScktSrvr.zip



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2011.12.04;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.004 c
8-1221068545
Age
2008-09-10 21:42
2011.12.04
Работа с плеером


2-1313237802
Псарь
2011-08-13 16:16
2011.12.04
Как вывести растр через функцию DrawState?


15-1313146678
Псарь
2011-08-12 14:57
2011.12.04
Почему Твидиум всегда пишет "Не авторизован"?


1-1276514005
kukuruza
2010-06-14 15:13
2011.12.04
Помогите разобраться PChar SetString


8-1220951683
Konung
2008-09-09 13:14
2011.12.04
Рисовать на pf32bit битмапе





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский