Сабж возможен?
On Wed, 18 Jan 2006 17:26:37 +0000 (UTC); Igor Yegorkin wrote about 'два слушающих сокета в блокирующем режиме в одной программе':
IY> Сабж возможен?
В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно будет
только на одном сокете :)
Вот только почему бы не использовать неблокирующие сокеты, не пойму.
--
WBR, Vadim Goncharov. ICQ#166852181 mailto:vadim_n...@mail.ru
[Moderator of RU.ANTI-ECOLOGY][FreeBSD][http://antigreen.org][LJ:/nuclight]
> IY> Сабж возможен?
> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно будет
> только на одном сокете :)
Да вот экспериментирую.
> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
Ну, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп советует
использовать неблокирующие варианты, но всё же...
С одним слушающим сокетом работает,
а если добавить разных StartServer(...), то нет :(
unit net;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, WinSock, ScktComp;
type
TServerSocketParams = record
RemoteAddr:TSockAddr;
LocalAddr:TSockAddr;
end;
PServerSocketParams = ^TServerSocketParams;
TServerClientSocketParams = record
ClientSocketHandle:TSocket;
RemoteAddr:TSockAddr;
end;
PServerClientSocketParams = ^TServerClientSocketParams;
TFrame = class(TForm)
reLog: TRichEdit;
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
public
end;
var
Frame: TFrame;
ServerSocketHandle: TSocket;
FTraffic,FRedirectThreads:Integer;
FLock: TRTLCriticalSection;
implementation
{$R *.DFM}
function GetStringErrorWSA:string;
var e:Integer;
begin
e:=WSAGetLastError;
case e of
WSAEINTR: Result:='WSAEINTR'; // = (WSABASEERR+4);
[ой как много тут было вариантов]
WSANO_DATA: Result:='WSANO_DATA'; // = (WSABASEERR+1004);
else Result:='#'+IntToStr(e);
end;
Result:='Sockets error '+Result;
end;
procedure Log(AString:string);
const MaxLines = 300; MaxLineLen = 1024;
var i:Integer;
begin
EnterCriticalSection(FLock);
try
try
for i:=1 to Length(AString) do
if AString[i]=#13 then AString[i]:='|'
else if AString[i]<#32 then AString[i]:='_';
with Frame.reLog,Lines do
begin
if Count>=MaxLines then Delete(0);
if Length(AString)>MaxLineLen then
AString:=Copy(AString,1,MaxLineLen)+'...';
Add(AString);
Perform(EM_SCROLLCARET,0,0);
Perform(WM_VSCROLL,SB_LINEDOWN,0);
end;
except
Frame.Caption:='*'+Frame.Caption;
end;
finally
LeaveCriticalSection(FLock);
end;
end;
procedure Stat(Leave:Boolean; ATraffic:Integer);
begin
EnterCriticalSection(FLock);
try
Inc(FTraffic,ATraffic);
if Leave then Dec(FRedirectThreads)
else Inc(FRedirectThreads);
Log('* Потоков: '+IntToStr(FRedirectThreads)+'; трафик: '+IntToStr(FTraffic));
finally
LeaveCriticalSection(FLock);
end;
end;
procedure CritChk(Ok:Boolean; LastMess:string);
begin
if not Ok then begin Log(LastMess); Frame.Update; Sleep(999); Frame.Close; end;
end;
function IsAnyDataInSocket(Sck:WinSock.TSocket):Longint;
var FDSet:TFDSet; TimeVal:TTimeVal;
begin
FDSet.fd_count:=1;
FDSet.fd_array[0]:=Sck;
TimeVal.tv_sec:=0; TimeVal.tv_usec:=0;
Result:=Select(0,@FDSet,nil,nil,@TimeVal);
end;
function SendBuf(Socket:TSocket; var Buf; Len:Integer):Integer;
var Sent:Integer;
begin
Sent:=0;
repeat
Result:=Send(Socket,TByteArray(Buf)[Sent],Len,0);
if (Result>0)and(Result<>SOCKET_ERROR) then Inc(Sent,Result);
until (Sent >= Len)or(Result = SOCKET_ERROR);
end;
procedure ServerSocketClientThread(PServCliSockPar:PServerClientSocketParams);
stdcall;
const BufLen = $FFF;
var ATraffic,Size,Err:Integer; Errors:Boolean; Buf:PChar;
ServCliSocket,PureClientSocket:TSocket;
begin // gethostbyname по имени адрес
ServCliSocket:=PServCliSockPar^.ClientSocketHandle;
// создать дополнительный клиентский сокет к серверу
PureClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
CritChk(PureClientSocket<>INVALID_SOCKET,'Failed to create a
socket'#13+GetStringErrorWSA);
Err:=Connect(PureClientSocket,PServCliSockPar^.RemoteAddr,SizeOf(PServCliSockPar^.RemoteAddr)); if Err = SOCKET_ERROR then Log('Failed to connect the socket'#13+GetStringErrorWSA) else begin ATraffic:=0; Stat(False,ATraffic); GetMem(Buf,BufLen); // читать и писать - просто перенаправлять Errors:=False; repeat // узнать, сколько пришло данных от клиента Err:=IsAnyDataInSocket(ServCliSocket); if Err = SOCKET_ERROR then begin Errors:=True; Break; end; if Err>0 then begin // получить запрос от клиента Err:=Recv(ServCliSocket,Buf^,BufLen-1,0); if Err = 0 then Break; // connection closed gracefully if Err = SOCKET_ERROR then begin Errors:=True; Break; end; Size:=Err; Log('<< '+Buf); // отправить на сервер Inc(ATraffic,Size); if SendBuf(PureClientSocket,Buf^,Size) = SOCKET_ERROR then begin Errors:=True; Break; end; end; Sleep(99); // todo тут будет адаптивный замедлитель трафика // узнать, е!
сть ли данные от сервера на чтение Err:=IsAnyDataInSocket(PureClientSocket); if Err = SOCKET_ERROR then begin Errors:=True; Break; end; if Err>0 then begin // получить ответ от сервера Err:=Recv(PureClientSocket,Buf^,BufLen-1,0); if Err = 0 then Break; // connection closed gracefully if Err = SOCKET_ERROR then begin Errors:=True; Break; end; Size:=Err; Log('>> '+Buf); // переправить ответ сервера клиенту Inc(ATraffic,Size); if SendBuf(ServCliSocket,Buf^,Size) = SOCKET_ERROR then begin Errors:=True; Break; end; end; until Errors; if Errors then Log(GetStringErrorWSA); FreeMem(Buf); Stat(True,ATraffic); end; // закрыть if PureClientSocket<>INVALID_SOCKET then CloseSocket(PureClientSocket); if ServCliSocket<>INVALID_SOCKET then CloseSocket(ServCliSocket); FreeMem(PServCliSockPar);end;procedure ServerSocketAcceptThread(PServParam:PServerSocketParams); stdcall;var Sz,Err:Integer; AcceptedAddr:TSockAddr;!
NewSocketHandle:TSocket;ThreadID:DWORD; PServCliSockPar:PSer!
verClien
tSocketParams;begin // создать слушающий серверный сокет, раздатчик сокетов ServerSocketHandle:=Socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); CritChk(ServerSocketHandle<>INVALID_SOCKET,'Failed to create asocket'#13+GetStringErrorWSA); Err:=Bind(ServerSocketHandle,PServParam^.LocalAddr,SizeOf(PServParam^.LocalAddr)); CritChk(Err<>SOCKET_ERROR,'Failed to bind the socket'#13+GetStringErrorWSA); Err:=Listen(ServerSocketHandle,SOMAXCONN); CritChk(Err<>SOCKET_ERROR,'Failed to listen the socket'#13+GetStringErrorWSA); repeat Sz:=SizeOf(AcceptedAddr); NewSocketHandle:=Accept(ServerSocketHandle,@AcceptedAddr,@Sz); if NewSocketHandle<>INVALID_SOCKET then begin // оформление параметров; память освободит поток перед завершением GetMem(PServCliSockPar,SizeOf(TServerClientSocketParams)); with PServCliSockPar^ do begin ClientSocketHandle:=NewSocketHandle; Move(PServParam^.RemoteAddr,RemoteAddr,SizeOf(RemoteAddr)); end; // запуск потока перенаправления Err:=!
CreateThread(nil,0,@ServerSocketClientThread,PServCliSockPar,0,ThreadID); CritChk(Err<>0,'CreateThread failed'); Log('Accepted'+inet_ntoa(AcceptedAddr.sin_addr)+':'+IntToStr(AcceptedAddr.sin_port)); end else Log('ERROR: Failed to accept the socket'); until Application.Terminated; if ServerSocketHandle<>INVALID_SOCKET then CloseSocket(ServerSocketHandle); FreeMem(PServParam);end;function LookupName(const Name:string):TInAddr;var HostEnt:PHostEnt; InAddr:TInAddr;begin InAddr.S_addr:=Inet_addr(PChar(Name)); if InAddr.S_addr = u_long(INADDR_NONE) then begin HostEnt:=gethostbyname(PChar(Name)); FillChar(InAddr,SizeOf(InAddr),0); if HostEnt<>nil then begin with InAddr,HostEnt^ do begin S_un_b.s_b1:=h_addr^[0]; S_un_b.s_b2:=h_addr^[1]; S_un_b.s_b3:=h_addr^[2]; S_un_b.s_b4:=h_addr^[3]; end; end; Result:=InAddr; end;end;procedure StartServer(LocalPort,RemotePort:DWORD; RemoteAddress:string);var Err,ThreadID:DWORD; PServP!
aram:PServerSocketParams;begin GetMem(PServParam,SizeOf(TServe!
rSocketP
arams)); with PServParam^ do begin FillChar(RemoteAddr,SizeOf(RemoteAddr),0); FillChar(LocalAddr,SizeOf(LocalAddr),0); RemoteAddr.sin_family:=AF_INET; LocalAddr.sin_family:=AF_INET; RemoteAddr.sin_addr:=LookupName(RemoteAddress); RemoteAddr.sin_port:=htons(RemotePort); LocalAddr.sin_addr.s_addr:=INADDR_ANY; LocalAddr.sin_port:=htons(LocalPort); end; // память освободит поток в конце своей работы Err:=CreateThread(nil,0,@ServerSocketAcceptThread,PServParam,0,ThreadID); CritChk(Err<>0,'CreateThread failed');end;procedure TFrame.FormActivate(Sender: TObject);begin FRedirectThreads:=0; FTraffic:=0; StartServer(80,80,'ya.ru'); С одним работает, а если добавить разных StartServer(...), то нет :(end;procedure TFrame.FormCreate(Sender: TObject);var Err:Integer; WData:TWSAData;begin InitializeCriticalSection(FLock); Err:=WSAStartup(MakeWord(1,1),WData); CritChk(Err=0,'Failed to initialize WinSocket,error #'+IntToStr(Err));end;procedure TFrame.FormDestroy(Sender: TOb!
ject);begin // todo // пока что нельзя освободить FLock и WSA, потому что потоки завершаться позже // DeleteCriticalSection(FLock); // WSACleanup;end;end.
On Wed, 18 Jan 2006 18:49:51 +0000 (UTC); Igor Yegorkin wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
IY>> Сабж возможен?
>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно будет
>> только на одном сокете :)
IY> Да вот экспериментирую.
>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY> Ну, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп советует
IY> использовать неблокирующие варианты, но всё же...
Блокирующий режим предназначен для программ с одним сокетом.
IY> С одним слушающим сокетом работает,
IY> а если добавить разных StartServer(...), то нет :(
IY> unit net;
И даже глядеть код не хочу. Не предназначено оно для такого.
> IY>> Сабж возможен?
> Блокирующий режим предназначен для программ с одним сокетом.
> IY> С одним слушающим сокетом работает,
> IY> а если добавить разных StartServer(...), то нет :(
> И даже глядеть код не хочу. Не предназначено оно для такого.
Вот, невнимательно я хелп читал. Но ещё виноват автор одной книги,
он среди недостатков блокирующих сокетов не указал однопоточность.
IY>> Сабж возможен?
VG> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
VG> будет только на одном сокете :)
VG> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
Логика работы с ними проще?
bb All
IY> From: "Igor Yegorkin" <yego...@ukrpost.net>
IY> Hi, Vadim Goncharov
>> IY> Сабж возможен?
>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>> будет только на одном сокете :)
IY> Да вот экспериментирую.
>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY> советует использовать неблокирующие варианты, но всё же...
IY> С одним слушающим сокетом работает,
IY> а если добавить разных StartServer(...), то нет :(
У тебя тут минимум RTL на многопоточный вариант работы не перешла.
Почему TThread не используешь?
bb All
IY> From: "Igor Yegorkin" <yego...@ukrpost.net>
IY> Hi, Vadim Goncharov
>> IY> Сабж возможен?
>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>> будет только на одном сокете :)
IY> Да вот экспериментирую.
>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
>>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>>> будет только на одном сокете :)
IY>> Да вот экспериментирую.
>>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY>> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY>> советует использовать неблокирующие варианты, но всё же...
VG> Блокирующий режим предназначен для программ с одним сокетом.
это из чего следует?
bb All
On Thu, 19 Jan 2006 08:29:14 +0000 (UTC); Igor Yegorkin wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
IY>>> Сабж возможен?
>> Блокирующий режим предназначен для программ с одним сокетом.
IY>> С одним слушающим сокетом работает,
IY>> а если добавить разных StartServer(...), то нет :(
>> И даже глядеть код не хочу. Не предназначено оно для такого.
IY> Вот, невнимательно я хелп читал. Но ещё виноват автор одной книги,
IY> он среди недостатков блокирующих сокетов не указал однопоточность.
Так это же очевидно. Тем более, что формально ты их можешь использовать
несколько в одной нити - в клиентской программе какой-нибудь.
On Thu, 19 Jan 2006 11:02:24 +0000 (UTC); Alexey Cherepanov wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
IY>>> Сабж возможен?
VG>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
VG>> будет только на одном сокете :)
VG>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
AC> Логика работы с ними проще?
Так шашечки или ехать?
On Thu, 19 Jan 2006 11:11:38 +0000 (UTC); Alexey Cherepanov wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
>>>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>>>> будет только на одном сокете :)
IY>>> Да вот экспериментирую.
>>>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY>>> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY>>> советует использовать неблокирующие варианты, но всё же...
VG>> Блокирующий режим предназначен для программ с одним сокетом.
AC> это из чего следует?
Просто мозгами пораскинуть.
IY> From: "Igor Yegorkin" <yego...@ukrpost.net>
IY> Hi, Vadim Goncharov
>> IY> Сабж возможен?
>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>> будет только на одном сокете :)
IY> Да вот экспериментирую.
>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY> советует использовать неблокирующие варианты, но всё же...
IY> С одним слушающим сокетом работает,
IY> а если добавить разных StartServer(...), то нет :(
Да, еще, нужно заменить
=============================================
IY> var
IY> Frame: TFrame;
IY> ServerSocketHandle: TSocket;
IY> FTraffic,FRedirectThreads:Integer;
IY> FLock: TRTLCriticalSection;
=============================================
Хотя бы так
=============================================
var
Frame: TFrame;
FTraffic, FRedirectThreads: Integer;
FLock: TRTLCriticalSection;
threadvar
ServerSocketHandle: TSocket;
[хрум]
initialization
IsMultiThread:=True;
end.
=============================================
bb All
VG> Hi Alexey Cherepanov!
>>>>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>>>>> будет только на одном сокете :)
IY>>>> Да вот экспериментирую.
>>>>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY>>>> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY>>>> советует использовать неблокирующие варианты, но всё же...
VG>>> Блокирующий режим предназначен для программ с одним сокетом.
AC>> это из чего следует?
VG> Просто мозгами пораскинуть.
... то получается что
даже в блокирующием режиме, после accept сокетов как минимум 2 -
один серверый и один для подключившегося клиента :)
Да и по поводу заблокироватся на одном сокете в одном треде ты не прав...
функция select и телемаркет.
P.S.
Пример-то рабочий... хоть по твоим словам и не должно, а работает :))))
bb All
> threadvar
> ServerSocketHandle: TSocket;
упс! недосмотр, эти хэндлы у каждого потока свои.
Спасибо.
On Thu, 19 Jan 2006 13:46:01 +0000 (UTC); Alexey Cherepanov wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
>>>>>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться можно
>>>>>> будет только на одном сокете :)
IY>>>>> Да вот экспериментирую.
>>>>>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY>>>>> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY>>>>> советует использовать неблокирующие варианты, но всё же...
VG>>>> Блокирующий режим предназначен для программ с одним сокетом.
AC>>> это из чего следует?
VG>> Просто мозгами пораскинуть.
AC> ... то получается что
AC> даже в блокирующием режиме, после accept сокетов как минимум 2 -
AC> один серверый и один для подключившегося клиента :)
Я речь веду прежде всего о клиентских программах, которые делают
connect() - и у них сокет таки один. Подходит, впрочем, и для
итеративных серверов - у них один _используемый_ сокет будет, для
общения с клиентом, а к слушающему он вернется после его закрытия.
...Хотя, в случае inetd, сокет будет действительно только один
клиентский, а слушающий будет и вовсе отсутствовать.
AC> Да и по поводу заблокироватся на одном сокете в одном треде ты не прав...
AC> функция select и телемаркет.
Это уже следующий уровень силы ;)
AC> P.S.
AC> Пример-то рабочий... хоть по твоим словам и не должно, а работает :))))
Ммм.. где? Ему же надо было два блокируемых _слушающих_ сокета в одном
треде. Код я не читал, сразу сказал.
VG> From: Vadim Goncharov <vadimn...@tpu.ru>
VG> Hi Alexey Cherepanov!
VG> On Thu, 19 Jan 2006 13:46:01 +0000 (UTC); Alexey Cherepanov wrote about
VG> 'Re: два слушающих сокета в блокирующем режиме в одной программе':
>>>>>>> В разных тредах? Т.е. можно-то и одним тредом, но заблокироваться
>>>>>>> можно будет только на одном сокете :)
IY>>>>>> Да вот экспериментирую.
>>>>>>> Вот только почему бы не использовать неблокирующие сокеты, не пойму.
IY>>>>>> Hу, для начала блокирующий вариант хочу изучить. Знаю, что сам хэлп
IY>>>>>> советует использовать неблокирующие варианты, но всё же...
VG>>>>> Блокирующий режим предназначен для программ с одним сокетом.
AC>>>> это из чего следует?
VG>>> Просто мозгами пораскинуть.
AC>> ... то получается что
AC>> даже в блокирующием режиме, после accept сокетов как минимум 2 -
AC>> один серверый и один для подключившегося клиента :)
VG> Я речь веду прежде всего о клиентских программах, которые делают
VG> connect() - и у них сокет таки один.
VG>Подходит, впрочем, и для
VG> итеративных серверов - у них один _используемый_ сокет будет, для
VG> общения с клиентом, а к слушающему он вернется после его закрытия.
VG> ...Хотя, в случае inetd, сокет будет действительно только один
VG> клиентский, а слушающий будет и вовсе отсутствовать.
AC>> Да и по поводу заблокироватся на одном сокете в одном треде ты не
AC>> прав... функция select и телемаркет.
VG> Это уже следующий уровень силы ;)
здесь филиал Delphi.Chainik?? :)
AC>> P.S.
AC>> Пример-то рабочий... хоть по твоим словам и не должно, а работает :))))
VG> Ммм.. где? Ему же надо было два блокируемых _слушающих_ сокета в одном
В разных. Да и в одном через селект получится.
VG> треде. Код я не читал, сразу сказал.
bb All
Пишу сетевую программулину и вот понадобилось написать сетевой шлюз для почтовика.
Задача шлюза - дождаться соединения с инетом, при подключение клиента соединиться с серваком и обеспечивать передачу данных между почтовиком и pop3-сервером.
Логин задается ввиде: логин:имя_сервака, то есть vasya:pop3.vasya.ru.
Для реализации взял флеоновский http-proxy и попытался заточить его под pop3. Не вышло. Может кто знает как можно реализовать subj?
ЗЫ Сейчас посмотрел прогу MyGate, это шлюз для The Bat!, с помощью которого можно постить сообщения в ФИДО. Так там вроде индюшка используется.
С уважением,
Storm
WinAmp отдыхает...
> Пишу сетевую программулину и вот понадобилось написать сетевой шлюз для
> почтовика.
> Задача шлюза - дождаться соединения с инетом, при подключение клиента
> соединиться с
> серваком и обеспечивать передачу данных между почтовиком и pop3-сервером.
Вот как раз по теме обсуждения заработала моя тестовая версия:
http://splash.kiev.ua/depot/netsrv.rar
Только всеми рекомендуется сделать асинхронный неблокирующий вариант.
>> Пишу сетевую программулину и вот понадобилось написать сетевой шлюз для
>> почтовика.
>> Задача шлюза - дождаться соединения с инетом, при подключение клиента
>> соединиться с
>> серваком и обеспечивать передачу данных между почтовиком и pop3-сервером.
IY> Вот как раз по теме обсуждения заработала моя тестовая версия:
IY> http://splash.kiev.ua/depot/netsrv.rar
IY> Только всеми рекомендуется сделать асинхронный неблокирующий вариант.
Это кем? ты лучше у Анатолия на сайте почитай введение в Indy, там авторы
этот вопрос рассматривают и обосновывают блокирующий вариант.
bb All
> IY> Только всеми рекомендуется сделать асинхронный неблокирующий вариант.
> Это кем? ты лучше у Анатолия на сайте почитай введение в Indy, там авторы
> этот вопрос рассматривают и обосновывают блокирующий вариант.
Для программиста блокирующие сокеты - самые простые. Там даже синтаксис
вызовов простой.
Книгу читал как-то, там сказано, что блокирующие сокеты - самый простой метод,
но не эффективный (медленный и/или ресурсоёмкий). А вот вариант с
комплишн рутинз - самый лучший, но не везде идёт. Варианты с windows
messages, событиями и пр. - посередине.
Справка Windows SDK говорит, что функционирование блокирующих сокетов
обеспечивается искусственно и типа это криво ;) Но это уже проблемы Windows.
Thursday January 19 2006 19:30, Igor Yegorkin wrote to Alexey Cherepanov:
>> IY> Только всеми рекомендуется сделать асинхронный неблокирующий
>> IY> вариант.
>> Это кем? ты лучше у Анатолия на сайте почитай введение в Indy, там
>> авторы этот вопрос рассматривают и обосновывают блокирующий вариант.
IY> Для программиста блокирующие сокеты - самые простые. Там даже
IY> синтаксис вызовов простой.
IY> Книгу читал как-то, там сказано, что блокирующие сокеты - самый
IY> простой метод, но не эффективный (медленный и/или ресурсоёмкий). А вот
IY> вариант с комплишн рутинз - самый лучший, но не везде идёт. Варианты с
IY> windows messages, событиями и пр. - посередине.
IY> Справка Windows SDK говорит, что функционирование блокирующих сокетов
IY> обеспечивается искусственно и типа это криво ;) Hо это уже проблемы
IY> Windows.
По поводу кривости, наверное надо сначало посмотреть на тот код, что криво с
кривой реализацией работает.
Возращаясь к твоему исходнику:
1) в SendBuf возможен выход за пределы памяти
2) вместо вызова CreateThread рекоммендуется вызывать BeginThread все таки
3) понятия timeout проверки ошибочности сокета у тебя не существует
4) реализация CritChk просто потрясающая, Sleep(999) ни к чему хорошему не
доведет :-)
5) Интересно, а если создать 50 StartServer'ов, она будет продолжать работать
так же? У меня IDE сейсас не стоит, но сдается, что будут проблемы с 50
accept'ами сразу.
6) очень умно и много нагромаждений
Alexander
■ Mr. President of Piafi SoftIntl
■ E-Mail: m...@piafi.ru; ICQ: 6339061
> http://www.piafi.ru/
AC> Это кем? ты лучше у Анатолия на сайте почитай введение в Indy, там
AC> авторы этот вопрос рассматривают и обосновывают блокирующий вариант.
Примерно через месяц или ранее будет готов полный первод одного из вариантов этой книги.
--
С уважением,
Анатолий Подгорецкий
IY> Для программиста блокирующие сокеты - самые простые. Там даже синтаксис
IY> вызовов простой.
IY> Книгу читал как-то, там сказано, что блокирующие сокеты - самый простой
IY> метод, но не эффективный (медленный и/или ресурсоёмкий). А вот вариант
Не слушай что говорят авторы, они не навидят Виндоус.
Проста только в простых случаях и эта простота относительная.
Ты писал 19 января 2006 г., 21:10:13:
AV> Возращаясь к твоему исходнику:
[поскипано]
Народ! Буду признателен, если будете выражаться по теме. Обсуждать тему "два слушающих сокета в блокирующем режиме в одной программе"
наверное можно по нетмейлу...
Спасибо.
On Thu, 19 Jan 2006 14:27:51 +0000 (UTC); Alexey Cherepanov wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
AC>>> Да и по поводу заблокироватся на одном сокете в одном треде ты не
AC>>> прав... функция select и телемаркет.
VG>> Это уже следующий уровень силы ;)
AC> здесь филиал Delphi.Chainik?? :)
Ну. Человек же сказал, что только начинает разбираться.
AC>>> P.S.
AC>>> Пример-то рабочий... хоть по твоим словам и не должно, а работает :))))
VG>> Ммм.. где? Ему же надо было два блокируемых _слушающих_ сокета в одном
AC> В разных.
Пардон, не заметил.
AC> Да и в одном через селект получится.
На блокируемых? Чревато. См. дедушку Стивенса, чем.
VG> Hi Alexey Cherepanov!
VG> On Thu, 19 Jan 2006 14:27:51 +0000 (UTC); Alexey Cherepanov wrote about
VG> 'Re: два слушающих сокета в блокирующем режиме в одной программе':
AC>>>> Да и по поводу заблокироватся на одном сокете в одном треде ты не
AC>>>> прав... функция select и телемаркет.
VG>>> Это уже следующий уровень силы ;)
AC>> здесь филиал Delphi.Chainik?? :)
VG> Hу. Человек же сказал, что только начинает разбираться.
У человека уже в примере селект был... как что с селектом уже он разобрался.
Наверно ;)
AC>>>> P.S.
AC>>>> Пример-то рабочий... хоть по твоим словам и не должно, а работает
AC>>>> :))))
VG>>> Ммм.. где? Ему же надо было два блокируемых _слушающих_ сокета в одном
AC>> В разных.
VG> Пардон, не заметил.
Дык...
AC>> Да и в одном через селект получится.
VG> Hа блокируемых? Чревато. См. дедушку Стивенса, чем.
Не читал. Где взять? Что пишет?
bb All
AP> You wrote to Igor Yegorkin on Thu, 19 Jan 2006 16:06:16 +0000 (UTC):
AC>> Это кем? ты лучше у Анатолия на сайте почитай введение в Indy, там
AC>> авторы этот вопрос рассматривают и обосновывают блокирующий вариант.
AP> Примерно через месяц или ранее будет готов полный первод одного из
AP> вариантов этой книги.
По какой версии Indy? 9 или 10?
А так всё очень здорово написано, СПАСИБО!!!
bb All
> 1) в SendBuf возможен выход за пределы памяти
Как?
function SendBuf(Socket:TSocket; var Buf; Len:Integer):Integer;
var Sent:Integer;
begin
Sent:=0;
repeat
Result:=Send(Socket,TByteArray(Buf)[Sent],Len,0);
if (Result>0)and(Result<>SOCKET_ERROR) then Inc(Sent,Result);
until (Sent >= Len)or(Result = SOCKET_ERROR);
end;
> 2) вместо вызова CreateThread рекоммендуется вызывать BeginThread все таки
"thereby making the heap thread-safe" с этим понятно.
А просто выполнить IsMultiThread := TRUE нельзя?
> 3) понятия timeout проверки ошибочности сокета у тебя не существует
это где?
> 4) реализация CritChk просто потрясающая, Sleep(999) ни к чему хорошему не
> доведет :-)
Взято из отладочной версии левого проекта. А что плохого в Sleep?
> 5) Интересно, а если создать 50 StartServer'ов, она будет продолжать работать
> так же? У меня IDE сейсас не стоит, но сдается, что будут проблемы с 50
> accept'ами сразу.
как решить проблему?
Friday January 20 2006 11:58, Igor Yegorkin wrote to Alexander Vedjakin:
>> 1) в SendBuf возможен выход за пределы памяти
IY> Как?
IY> function SendBuf(Socket:TSocket; var Buf; Len:Integer):Integer;
IY> var Sent:Integer;
IY> begin
IY> Sent:=0;
IY> repeat
>>> IY> Result:=Send(Socket,TByteArray(Buf)[Sent],Len,0);
IY> if (Result>0)and(Result<>SOCKET_ERROR) then Inc(Sent,Result);
IY> until (Sent >= Len)or(Result = SOCKET_ERROR);
IY> end;
Вне зависимости от того, сколько ты уже послал, ты всегда шлешь весь массив.
Sent у тебя увеличивается, но Len не уменьшается.
>> 2) вместо вызова CreateThread рекоммендуется вызывать BeginThread
>> все таки
IY> "thereby making the heap thread-safe" с этим понятно.
IY> А просто выполнить IsMultiThread := TRUE нельзя?
Можно, но не рекомендуется :) Hо заметь, что BeginThread и CreateThread в
качестве параметра ФУHКЦИИ используют тип function (p: pointer): dword у тебя
же описано function (p:pointer): void
>> 3) понятия timeout проверки ошибочности сокета у тебя не существует
IY> это где?
IsAnyDataInSocket, в вызове Select
function IsAnyDataInSocket(Sck:WinSock.TSocket):Longint;
var FDSet,FDSet2:TFDSet; TimeVal:TTimeVal;
begin
FDSet.fd_count:=1;
FDSet.fd_array[0]:=Sck;
FDSet2 := FDSet;
TimeVal.tv_sec:=30; // хотя бы 30 секунд подождать
TimeVal.tv_usec:=0;
Result:=Select(0,@FDSet,nil,@FDSet2,@TimeVal);
if FDSet2.fd_count <> 0 then Result := -1;
end;
А по большому счету: тебе желательно запихнуть в Select все два сокета, из
которого первого пришли данные, из того и бум читать, отсылая прочитанное в
соседний сокет.
>> 4) реализация CritChk просто потрясающая, Sleep(999) ни к чему
>> хорошему не доведет :-)
IY> Взято из отладочной версии левого проекта. А что плохого в Sleep?
Возможность повесить окно, а так больше ничего :-)
ServerSocketHandle:=Socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
CritChk(ServerSocketHandle<>INVALID_SOCKET,'Failed to create a
socket'#13+GetStringErrorWSA);
Err:=Bind(ServerSocketHandle,PServParam^.LocalAddr,SizeOf(PServParam^.LocalAdd
r));
CritChk(Err<>SOCKET_ERROR,'Failed to bind the socket'#13+GetStringErrorWSA);
Err:=Listen(ServerSocketHandle,SOMAXCONN);
CritChk(Err<>SOCKET_ERROR,'Failed to listen the socket'#13+GetStringErrorWSA);
repeat
....
until Application.Terminated;
При ошибке в создании сокета, как думаешь: сколько раз будет вызван Sleep?
>> 5) Интересно, а если создать 50 StartServer'ов, она будет продолжать
>> работать так же? У меня IDE сейсас не стоит, но сдается, что будут
>> проблемы с 50 accept'ами сразу.
IY> как решить проблему?
Все тот же Select
А вот совсем и не умерла эха =)
Продолжаем латать самодельный сервер http://splash.kiev.ua/depot/netsrv.rar
> >> 1) в SendBuf возможен выход за пределы памяти
> IY> Как?
> Вне зависимости от того, сколько ты уже послал, ты всегда шлешь весь массив.
Спасибо, самое интересное, что для маленького буфера ошибочный вариант
ни разу не выполнился.
> IY> А просто выполнить IsMultiThread := TRUE нельзя?
> Можно, но не рекомендуется :) Hо заметь, что BeginThread и CreateThread в
> качестве параметра ФУHКЦИИ используют тип function (p: pointer): dword у тебя
> же описано function (p:pointer): void
Ну это я взял из Delphi5\Source\Vcl\forms.pas:
...
procedure HintMouseThread(Param: Integer); stdcall;
....
HintThread := CreateThread(nil, 1000, @HintMouseThread, nil, 0, ThreadID);
...
> >> 3) понятия timeout проверки ошибочности сокета у тебя не существует
И чем это черевато? Чтение или запись ошибочного сокета покажут
ошибку потом. Может ли сокет закрыться незаметно?
Можно положиться на отсутствие терпения у клиента или сервера,
подключённых к нашей программе, "вечных" подключений не будет.
> А по большому счету: тебе желательно запихнуть в Select все два сокета, из
> которого первого пришли данные, из того и бум читать, отсылая прочитанное в
> соседний сокет.
Как узнать, из какого именно сокета пришли данные, если передать два сокета?
>>> 5) Интересно, а если создать 50 StartServer'ов, она будет продолжать
>>> работать так же? У меня IDE сейсас не стоит, но сдается, что будут
>>> проблемы с 50 accept'ами сразу.
> IY> как решить проблему?
> Все тот же Select
Куда его прикрутить?
AP>> You wrote to Igor Yegorkin on Thu, 19 Jan 2006 16:06:16 +0000 (UTC):
AC>>> Это кем? ты лучше у Анатолия на сайте почитай введение в Indy, там
AC>>> авторы этот вопрос рассматривают и обосновывают блокирующий вариант.
AP>> Примерно через месяц или ранее будет готов полный первод одного из
AP>> вариантов этой книги.
AC> По какой версии Indy? 9 или 10?
AC> А так всё очень здорово написано, СПАСИБО!!!
По 9 версии, но есть глава и по 10
К сожалению, у меня не окончательная версия книги, а preview
> AC> А так всё очень здорово написано, СПАСИБО!!!
> По 9 версии, но есть глава и по 10
> К сожалению, у меня не окончательная версия книги, а preview
Сидим, читаем http://podgoretsky.com/ftp/Docs/Internet/IntroIndy/
AC>>> А так всё очень здорово написано, СПАСИБО!!!
??>> По 9 версии, но есть глава и по 10
??>> К сожалению, у меня не окончательная версия книги, а preview
IY ты не понял, эта ссылка на укороченую версию, завлекаловка, а я сейчас перевожу полную книгу, размер где то 130 страниц, 21 глава.
Оригинальное название Indy In Depth
> IY ты не понял, эта ссылка на укороченую версию, завлекаловка, а я сейчас
> перевожу полную книгу, размер где то 130 страниц, 21 глава.
> Оригинальное название Indy In Depth
А можно ссылочку на одну из двух языковых версий?
AC>>>> А так всё очень здорово написано, СПАСИБО!!!
??>>> По 9 версии, но есть глава и по 10
??>>> К сожалению, у меня не окончательная версия книги, а preview
AP> IY ты не понял, эта ссылка на укороченую версию, завлекаловка, а я сейчас
AP> перевожу полную книгу, размер где то 130 страниц, 21 глава.
AP> Оригинальное название Indy In Depth
Может быть можно чем-то помочь?
bb All
??>> IY ты не понял, эта ссылка на укороченую версию, завлекаловка, а я
??>> сейчас перевожу полную книгу, размер где то 130 страниц, 21
??>> глава. Оригинальное название Indy In Depth
IY> А можно ссылочку на одну из двух языковых версий?
Укорочения версия на моем сайте, а полная пока в работе
--
С уважением,
Анатолий Подгорецкий
AC>>>>> А так всё очень здорово написано, СПАСИБО!!!
??>>>> По 9 версии, но есть глава и по 10
??>>>> К сожалению, у меня не окончательная версия книги, а preview
AP>> IY ты не понял, эта ссылка на укороченую версию, завлекаловка, а я
AP>> сейчас перевожу полную книгу, размер где то 130 страниц, 21
AP>> глава. Оригинальное название Indy In Depth
AC> Может быть можно чем-то помочь?
Ну только если есть окончательный оригинал на английском.
On Fri, 20 Jan 2006 07:19:34 +0000 (UTC); Alexey Cherepanov wrote about 'Re: два слушающих сокета в блокирующем режиме в одной программе':
AC> У человека уже в примере селект был... как что с селектом уже он разобрался.
AC> Наверно ;)
Пусть сам скажет, зачем гадать :)
AC>>> Да и в одном через селект получится.
VG>> Hа блокируемых? Чревато. См. дедушку Стивенса, чем.
AC> Не читал. Где взять? Что пишет?
Ну это ж классика. W.R. Stevens, Unix network programming - тыща страниц
с гаком... Если коротко - если та сторона закроет соединение до вызова
нами accept(), этот наш accept() заблокируется.
Ты писал 20 января 2006 г., 17:36:53:
> А вот совсем и не умерла эха =)
> Продолжаем латать самодельный сервер
> http://splash.kiev.ua/depot/netsrv.rar
Вопрос, а на фига там ограничение на 2 метра?
Так, фича для будушего использования или нужная весчь, без которой некоторые что-то работать не будет.
Просто я тут прикинул. По ходу дела этот самый MaxTraffic не нужен. Все и без него работает... Или все же он нужен потому, что при выходе за предел в 2 метра что-то работать перестанет?
С уважением,
Storm
Сейчас WinAmp играет: Bullet For My Valentine - Hand Of Blood
>> http://splash.kiev.ua/depot/netsrv.rar
> Вопрос, а на фига там ограничение на 2 метра?
> Так, фича для будушего использования или нужная весчь, без которой некоторые
> что-то работать не будет.
При превышении трафика программа должна закрыться. Это не всем нужная фича, её
можно удалить.
Ты писал 21 января 2006 г., 20:40:13:
Захотел сделать разметку писем на лету (кому предназначено, так для прикола).
В функции ServerSocketClientThread объявил переменные:
WorkStr : String;
MailMes : TStrings;
и сделал примерно так:
WorkStr:=String(Buf);
if Pos('Subject:', WorkStr) > 0 then
begin
MailMes:=TStringList.Create;
MailMes.Add(WorkStr);
Obrabotka(MailMes.Text);
//В целях экономии скипаю код обработки\\
Buf:=PChar(MailMes.Text);
MailMes.Free;
Принимаю почту. Доходит до приема письма (соединение с серваком и авторизация проходит нормально), пишет что принимает письмо и зависает. Рву коннект руками.
Лог бата (The Bat!) обрывается на последних строчках письма.
Как лечить?
И еще. Если сервак запустить до коннекта с инетом, то он по сути не работает, а если после - то все ок.
С уважением,
Storm
Сейчас WinAmp играет: Avenged Sevenfold - Blinded In Chains
> Buf:=PChar(MailMes.Text);
> MailMes.Free;
А может лучше так
Buf := StrNew(PChar(MailMes.Text));
или так (там StrNew внутри)
Buf := MailMes.GetText;
ну а далее посмотрим.
Ты писал 22 января 2006 г., 13:47:39:
> А может лучше так
А куда StrDispose прикручивать?
> ну а далее посмотрим.
Еще не пробовал.
Ты писал 22 января 2006 г., 13:47:39:
> ну а далее посмотрим.
Все равно не работает... :(
> И еще. Если сервак запустить до коннекта с инетом, то он по сути не работает,
> а если после - то все ок.
Это потому, что компьютеру до коннекта с инетом не выделен IP-адрес для
соответствующего сетевого интерфейса.
Ты писал 22 января 2006 г., 17:35:20:
> Это потому, что компьютеру до коннекта с инетом не выделен IP-адрес для
> соответствующего сетевого интерфейса.
А по поводу остального?
(Про некорректную работу)
VG> Hу это ж классика. W.R. Stevens, Unix network programming - тыща страниц
VG> с гаком... Если коротко - если та сторона закроет соединение до вызова
VG> нами accept(), этот наш accept() заблокируется.
Проверил. Все нормально.
xp2sp2 d7 ws2.2
bb All