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

Вниз

WinSock + Threads!   Найти похожие ветки 

 
Nigger   (2003-04-27 19:09) [0]

Мастера... у меня большая проблемма! Пишу программу клиент с WinSock"ом и потоками... если делаю чтоб несколько потоков было,то на вторые пакеты ответ с сервера не идет (создается впечатление, что это один сокет с N-м количеством одинаковых пакетов - то есть все сокеты работают как один "большой") Может все дело в блокированых и неброкированых сокетах или потоках???
Как вообще реализовать многопоточное соединение клиента на WinSock???
И ещё: прога ругается что OutOfMemory - но это похоже, что с другим связано. И про recv хотел ещё спросить... что за странный тип переменной там используется - может я его как то не правильно использую? Помогите разобраться!

var
Buff: pchar;
z: string;

GetMem(Buff,size);
FillChar(Buff[1],size,0);
ret:=recv(S,Buff^,size,0);
z:=buff;
FreeMem(Buff, size);


 
Illusion   (2003-04-27 21:03) [1]

Pchar = pointer char.
Аналог char* в С и С++.
историческая справка: строки бывают двух типов. В паскале широко применятся Pascal стринг. Это когда в первом (читай нулевом) байте записанна длинна строки, а ждалее идёт сама строка. D C++ (вернее в билдере) сия фигня реализовнна в классе AnsiString, который эмулирует паскаль строчки. Но в С/С++ широко применяется Pointer String. Это когда строка начинается с нулевого символа. И символ с кодом 0 означает конец строки.
т.к. все функции в винсоке заточенны под С/С++, то соответвестнно возращают значение в используемых парамерах. Чё тебе делать? вот что...

var
Buff: pchar;
z: string;
ret:integer;

GetMem(Buff,size);
buff[0] := 0;
ret:=recv(S,Buff^,size,0);
buff[ret] := 0;
z:=buff;
FreeMem(Buff, size);

ljk;yjvar
Buff: pchar;
z: string;

GetMem(Buff,size);
FillChar(Buff[1],size,0);
ret:=recv(S,Buff^,size,0);
z:=buff;
FreeMem(Buff, size);

должно работать.


 
Illusion   (2003-04-27 21:08) [2]

всё что ние, после бреда - меня прогючила, не обращать внимание :)


 
Nigger   (2003-04-28 00:12) [3]

Спасибо конечно, но ситуация никаким макаром не изменилась(Опять какую то ошибку выдает насчет pchar)... и меня по прежнему интересует вопрос насчет сокетов (см. выше)


 
Alex Konshin   (2003-04-28 07:41) [4]

В Winsock 1.x события приходят через очередь сообщений Windows. Если у тебя несколько потоков, то эти потоки тоже должны обрабатывать эти сообщения. TThread их просто игнорирует (может я и не прав, мне сейчас лень глядеть в код).

На мой взгляд, гораздо проще использовать Winsock2, особенно в многопоточных приложениях.
Работай через функции WSA* ассинхронно (overlapped и/или completion routines) и жди событий с помощью WSAWaitForMultipleEvents - так намного понятнее, когда работаешь в нескольких потоках.
Например, используй WSARecv, в параметре lpOverlapped передаешь адрес структуры, в поле hEvent которой вписываешь handle события. Потом жди этого события по WSAWaitForMultipleEvents.
Можешь еще в completion routine выставлять какое-нибудь событие, это тоже премлемое решение. А остальное - это уж как тебе нравиться и как в задаче требуется, много разных вариантов можно придумать.

Про функции читай MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/windows_sockets_start_page_2.asp
Например, для WSAWaitForMultipleEvents:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/wsawaitformultipleevents_2.asp

Чтоб работать с Winsock2 в Delphi бери мой юнит с моего сайта:
http://home.earthlink.net/~akonshin/index.htm
В Delphi7 (точнее, в Indy) есть IdWinsock2.pas, это тоже подойдет, но реально это чуть урезанный мой юнит (посмотри копирайт).


 
Polevi   (2003-04-28 09:44) [5]

2Alex Konshin © (28.04.03 07:41)
ИМХО не в тему, вопрошающий пытается работать в блокирующем режиме, судя по всему, раз несколько потоков ему надо


 
Digitman   (2003-04-28 10:07) [6]


> Как вообще реализовать многопоточное соединение клиента
> на WinSock???


Никак.
Вызов Winsock-ф-ций для управления гнездовым транспортом допускается в каждый момент времени только в контексте одного кодового потока.

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



 
Digitman   (2003-04-28 10:10) [7]

хотя winsock и использует крит.секции для блокирования гнездовых ресурсов при мультипоточном доступе к транспортным ф-циям, полагаться на это не следует


 
Nigger   (2003-04-28 23:45) [8]

2Polevi: я пытаюсь понять на чем это вобще можно сделать и как это будет работать - пока ниначем не получается.
2Digitman:
< Как вообще реализовать многопоточное соединение клиента
< на WinSock???
> Никак.
Вот тут я совсем не знаю что сказать, а как тогда бывают такие программы??? Например tetroPWD... или есть в статье "взлом мыла" (кстати почти везде валяется)исходник на делфи многопоточного клиента к pop3 серверу! - что самое странное с этим кодом твариться тоже самое что и с моим - все работает как один сокет....
Не знаю что и делать.
2Alex Konshin:
мысль об этом - что нужен winsock2, просто я раньше думал что я его и использую....
И ещё один вопрос: для создания такой программы нужно делать привязку данного сокета к адресу (bind etc)????


 
Nigger   (2003-04-28 23:49) [9]

Кхм... и ещё, как я понял для многопоточности нужен блокирующий режим. так ли это? если так, то как его на winsock включить, или он по дефолту поставлен??? (Страрые функции WSAiSBlocking Hook etc уже устарели)


 
Nigger   (2003-04-28 23:59) [10]

2Alex Konshin again:
Хоть в том, что ты сказал разобрался...огромное спасибо....
Кому надо почитать про это - вот страничка:
http://www.sources.ru/cpp/cpp_network_evets_winsock2.shtml


 
Alex Konshin   (2003-04-29 05:15) [11]


> 2Alex Konshin © (28.04.03 07:41)
> ИМХО не в тему, вопрошающий пытается работать в блокирующем
> режиме, судя по всему, раз несколько потоков ему надо

Как это не в тему? Вот как раз-таки под Winsock 1.x пытаться работать в нескольких потоках и есть извращение.
И к тому же winsock 1.x под NT+ реализован как wrapper вокруг Winsock2. Зачем вам лишний слой, который еще и не добавляет, а уменьшает функциональность?



 
Alex Konshin   (2003-04-29 05:29) [12]

2Nigger: делай как я сказал. В режиме overlapped ты можешь запускать несколько операций одновременно (хоть с одним сокетом, хоть с несколькими). Если же еще и грамотно организовать цикл ожидания-обработки, то вообще может и не понадобиться несколько нитей, ну или просто имей пул нитей и одну нить, которая ждет завершения операций и сразу же отдает полученное событие первой свободной нити. Короче, все на твое усмотрение, как сделаешь так и будет. На мой взгляд модель в Winsock2 даже проще и понятнее, забудь о блокирующем режиме как о кошмарном сне.


 
Digitman   (2003-04-29 08:39) [13]


> Nigger


Под "клиентом" я понимаю некое гнездо, созданное процессом клиентского приложения и установившее соединение с гнездом, созданным процессом серверного приложения

Ты спросил :

> Как вообще реализовать многопоточное соединение клиента
> на WinSock


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


> как тогда бывают такие программы


Это - совершенно иной вопрос с иным контекстом !


> многопоточного клиента к pop3 серверу!


в процессом кл.приложения создается N код.потоком, в ходе работы каждого из которых создается ОТДЕЛЬНОЕ гнездо (ассоциированное с отдельным код.потоком) и устанавливается соединение с ОТДЕЛЬНЫМ гнездом сервера


 
Polevi   (2003-04-29 09:19) [14]

>Alex Konshin © (29.04.03 05:29)
>пытаться работать в нескольких потоках и есть извращение
на этот счет существуют разные точки зрения, хотя я тоже приверженец асинхронного режима


 
Nigger   (2003-04-29 11:59) [15]

2Alex Konshin:
Я уже совсем этим законопатился по самое улыбаться... Не мог бы ты привести простейший (работающий) код для инициализации, подключения, отправки и приема данных в асинхронном режиме под WSA функциями... очень прошу! Потому, что я сел за делфи только три недели назад и толком не знаю ни структуры ни каких-нибудь особенных переменных etc... А если можешь - скинь готовый проект с твоим юнитом, буду жутко благодарен, т.к я думаю на разгребание WS функций уйдет неделя или даже не одна...
2Digitman: в процессом кл.приложения создается N код.потоком, в ходе работы каждого из которых создается ОТДЕЛЬНОЕ гнездо (ассоциированное с отдельным код.потоком) и устанавливается соединение с ОТДЕЛЬНЫМ гнездом сервера
^^^^^^^^
я про это и хотел сказать... я не так просто выразился


 
Illusion   (2003-04-29 12:37) [16]

смысл использовать WSAWaitForMultipleEvents, если в винде есть WSAsyncSelect? С ним на много удобней реализовывать ансихнорнные протоколы, когда сообщение может придти в любую секунду, и совесм не факт, что оно придёт, или придёт тогда, когда его будут ждать... Использую эту функцию можно вообще про треды забыть. Всё будет скидыватся в обрабочтик (который сам задаш в Application::OnMessage)...

2 Nigger, могу скинуть готовые классы для работы с TCP и UDP. ТОлько они написанны на С++ и мною.. Так что за безглючность не отечаю :).


 
Polevi   (2003-04-29 12:52) [17]

2Nigger © (29.04.03 11:59)
посмотри как сделано у борланда - scktcomp.pas

2Illusion © (29.04.03 12:37)
если сообщений не ждать c WSASyncSelect тоже ничего не придет


 
Nigger   (2003-04-29 17:46) [18]

2Illusion:
Спасибо... я лучше со старыми классами поработаю - копаться в чем то новом ещё больше времени убьет.
2Polevi:
Смотрел, мало что понял... мне хотябы простой пример посмотреть.


 
Alex Konshin   (2003-04-29 22:30) [19]

2 Polevi: НЕ ВЫДИРАЙ ФРАЗЫ ИЗ КОНТЕКСТА. Я сказал:

Вот как раз-таки под Winsock 1.x пытаться работать в нескольких потоках и есть извращение.

Согласись, смысл совсем иной.

2 Illusion: Надо ждать почти всегда. Обработка либо должна быть быстрой, либо должна передаваться другим нитям. WSAAsyncSelect работает через очередь сообщений windows, которая привязана к конкретной нити (у тебя к главной нити VCL), так что тебе повезло, что ты и не пытался работать этой функцией с несколькими потоками. Я не говорю, что это невозможно, я говорю, что это будет выглядеть не так просто, как ты думаешь - нужно будет самому организовывать цикл обработки сообщений windows, а учитывая еще и то, что TThread сам создает окно, то ты поимешь много развлечений и надолго. При этом ты не получаешь никакой выгоды, только лишний повод для мата. Работа же через Event намного прозрачнее и проще для понимания.

2 Nigger: У меня юнит слишком сложный, и если ты только что начал разбираться с Delphi, то тебе это будет просто не по зубам.
Он работает и с TCP, и с SPXII. Там создается по одной нити на каждое соединение, в каждой нити организуется цикл ожидания-обработки сообщений. Работает в overlapped режиме с completion routines. В добавок реализация классов для нитей своя (не TThread). Боюсь, что это будет слишком сложно для начинающего.


 
Illusion   (2003-04-29 23:44) [20]

2Alex Konshin, с несколькими потоками в ансихронном протоколе НИКОГДА не сталкивался... Хотя бы потому, что написать вещь, которую будет правильно всё разбирать и т.п.... Это ТАКОЙ ГИМОР! Чем меньше поток, тем лучше. Вообще всё можно запихнуть в ОДИН сокет... АБСОЛЮТНО ВСЁ. Главное - хорошо продумать каждый тип сообщений, и как это будет разбиратся. Но писать асинхронные протоколы в несколько потоков... Слишком много камней там...


 
Alex Konshin   (2003-04-30 03:54) [21]

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


 
Polevi   (2003-04-30 10:01) [22]

2Nigger © (29.04.03 17:46)
вот тебе ядро транспорта, если что пиши на e-mail

procedure TTransport.Execute;
var
msg:TMsg;
wc:WNDCLASS;
client:TClient;
i:integer;
begin
try
with wc do
begin
style:= 0;
lpfnWndProc:= @DefWindowProc;
cbClsExtra:= 0;
cbWndExtra:= 0;
hInstance:= 0;
hIcon:= 0;
hCursor:= 0;
hbrBackground:= 0;
lpszMenuName:= nil;
lpszClassName:= "FCTransportWndClass";
hInstance := HInstance;
end;
Windows.RegisterClass(wc);
FWindowHandle:=CreateWindowEx(WS_EX_TOOLWINDOW, wc.lpszClassName,
"", WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
if FWindowHandle<>0 then
SetEvent(FTransportReadyEvent); //флаг готовности транспорта

while not Terminated do
case MsgWaitForMultipleObjects(1, FWaitEvent, False, INFINITE, QS_ALLINPUT) of //ждем флаг завершения или сообщение windows
WAIT_OBJECT_0:
Terminate; //был установлен флаг завершения
WAIT_OBJECT_0 + 1:
with FClientList.LockList do //enter critical section
begin
try
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do //в очереди есть сообщения, выбираем их
begin
client:=nil;
try
client:=Items[msg.Message-WM_SOCKETMESSAGE]; //получем объект
if not Assigned(client) then
Continue
else
if HIWORD(msg.lParam)<>0 then
client.OnError(LOWORD(msg.lParam),HIWORD(msg.lParam))
else
case LOWORD(msg.lParam) of //тип события winsock
FD_ACCEPT:client.OnAccept;
FD_CONNECT:client.OnConnect;
FD_READ:Read(client);
FD_WRITE:Write(client);
FD_CLOSE:client.Free;
end;
except on E:Exception do
begin
if E.Message<>"" then Writeln(E.Message);
if Assigned(client) then client.Free;
end;
end;
end;
finally
FClientList.UnlockList; //leave critical section
end;
end;
end;
finally
DestroyWindow(FWindowHandle);
Writeln("Transport thread terminated.");
end;
end;


 
Polevi   (2003-04-30 10:08) [23]

constructor TClient.Create(ATransport: TTransport);
var
i:integer;
begin
FTransport:=ATransport;
FIndex:=-1;
with FTransport.FClientList.LockList do
try
for i:=0 to Count-1 do
if Items[i]=nil then
begin
FIndex:=i;
break;
end;
if FIndex=-1 then
FIndex:=Add(self)
else
Items[FIndex]:=self;
finally
FTransport.FClientList.UnlockList;
end;
end;


procedure TClient.Listen(AAddress:string;APort: Word);
begin
FSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
FAddr.sin_family := AF_INET;
if AAddress<>"" then
FAddr.sin_addr.s_addr := inet_addr(PChar(AAddress))
else
FAddr.sin_addr.s_addr := INADDR_ANY;
FAddr.sin_port := htons(APort);
if bind(FSocket, FAddr, SizeOf(FAddr))=SOCKET_ERROR then
raise Exception.Create(Format("Cannot bind on port %d",[APort]));

if Winsock.listen(FSocket, SOMAXCONN)=SOCKET_ERROR then
raise Exception.Create(Format("Cannot listen on port %d",[APort]));
WSAAsyncSelect(FSocket,FTransport.FWindowHandle,WM_SOCKETMESSAGE+FIndex, FD_ACCEPT or FD_CLOSE);
end;



procedure TClient.Connect(Address: string; Port: Word);
var
Err:DWORD;
begin
FSocket:=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
WSAAsyncSelect(FSocket,FTransport.FWindowHandle,WM_SOCKETMESSAGE+FIndex, FD_READ or FD_WRITE or FD_CLOSE or FD_CONNECT);
FAddr.sin_family:=AF_INET;
FAddr.sin_addr.s_addr :=inet_addr(PChar(Address));
FAddr.sin_port := htons(Port);
if WinSock.connect(FSocket, FAddr, SizeOf(FAddr))=SOCKET_ERROR then
begin
Err:=WSAGetLastError;
if Err<>WSAEWOULDBLOCK then
Raise Exception.Create(Format("Cannot connect to %s:%d - WSAGetLastError return %d",[Address,Port,Err]));
end
else
OnConnect;
end;


procedure TClient.Accept(AListenClient:TClient);
var
// Addr: TSockAddrIn;
Len: Integer;
begin
FListenClient:=AListenClient;
Len := SizeOf(FAddr);
FSocket:=WSAAccept(AListenClient.FSocket, @FAddr, @Len, @ConditionProc,DWORD(self));
if FSocket=INVALID_SOCKET then
raise Exception.Create(Format("Cannot accept client - WSAGetLastError return %d.",[WSAGetLastError]));
WSAAsyncSelect(FSocket,FTransport.FWindowHandle,WM_SOCKETMESSAGE+FIndex, FD_READ or FD_WRITE or FD_CLOSE);
FAddr.sin_port:=AListenClient.FAddr.sin_port;
end;


 
Alex Konshin   (2003-04-30 12:16) [24]

Не, я, конечно, понимаю, что гланды через разные отверстия выдирать можно...
Ну вот скажите, ну зачем транспорту окно, пусть даже и невидимое? И ведь один хрен используется MsgWaitForMultipleObjects и организуется цикл ожидания-обработки. И чем это лучше WSAWaitForMultipleEvents? Тем, что нужно еще написать кучу неотносящегося к делу кода? И ради чего? Так не проще ли по-нормальному сделать? Не, я понимаю, что в Winsock 1.x нельзя иначе, но кто ж вас заставляет его использовать-то?


 
Digitman   (2003-04-30 12:52) [25]


> Alex Konshin


В принципе, я с тобой согласен. Реализация транспорта с использованием событийной модели нотификации во многих случаях наглядней и эффективней.
Единственное, с чем могу не согласиться, так это с фразой :


> используется MsgWaitForMultipleObjects ..чем это лучше WSAWaitForMultipleEvents


WSAWaitForMultipleEvents не реализует ожидания сообщений потоку, только - ожидание событий. Если же потоку-диспетчеру требуется срочным образом известить транспортный поток о необходимости немедленно закрыть транспорт и "закруглиться по хозяйству", то наилучший способ сделать это - послать транспортному потоку сообщение с помощью PostThreadMessage. Но если трансп.поток в это время блокирован вызовом WSAWaitForMultipleEvents, он не сможет принять/диспетчеризовать/обработать это сообщение !
MsgWaitForMultipleObjects же, включая в себя полную функциональность от WSAWaitForMultipleEvents, позволяет еще и ждать сообщения, адресованные транспортному потоку.

т.о. желательный в этом случае "джентльменский набор" WS2-ф-ций :

MsgWaitForMultipleObjects + WSAEnumNetworkEvents



 
Polevi   (2003-04-30 13:55) [26]

>Alex Konshin © (30.04.03 12:16)
>Ну вот скажите, ну зачем транспорту окно, пусть даже и невидимое?
чтобы передать его хендл в WSAAsyncSelect

и насколько я помню ф-ии ожидания, подобные MsgWaitForMultipleObjects не могут ждать более 64 объектов, это довольно существенный недостаток для некоторых задач, транспорт который я привел используется в прокси сервере, на каждого клиента 2 сокета, так что в одном потоке может быть не более 32 клиентов, у меня их больше 100. Можно конечно организовать пул потоков, но это усложнит задачу.



 
Alex Konshin   (2003-05-01 10:44) [27]

2 Polevi: не надо мне объяснять как работает Winsock :)
Кто тебя заставляет для каждого сокета создавать Event?
Кто тебе мешает использовать completion routines?
Можно обойтись даже одним Event.

2 Digitman: а Event использовать религия не позволяет?
Если его еще и именованным сделать, то тогда не только из другого потока, но даже из другого процесса можно будет управлять. Кстати, я знаю, для чего, где и как применяется MsgWaitForMultipleObjects, и мне в любом случае непонятно, зачем там ждать QS_ALLINPUT, хотя оно конечно, чем шире откроешь, тем толще события ловить будешь :)

Ну и зачем транспорту окно?
Если приложению окно все-таки нужно, то пусть этим занимается та, нить, которой это более сподручно, а именно главная нить VCL.

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


 
Illusion   (2003-05-01 20:41) [28]

Блин, ну вы тут развели... Слов нет...


 
Polevi   (2003-05-03 11:52) [29]

2Alex Konshin © (01.05.03 10:44)
completion routines вообщето не имеет прямого отношения wincosk api, и некоторые уважаемые авторы не рекомендуют использовать ReadFile и WriteFile при работе с сокетами
и управлять транспортным потоком из другого процесса именованым ивентом это и есть извращение
и к флагам тоже не надо придираться
приведенный мной вариант транспорта весьма прост, и в этом его преимущество, имхо
а понты и пальцы не надо тут растопыривать
>Работает в overlapped режиме с completion routines.
я плакаль

с уважением


 
Polevi   (2003-05-04 09:29) [30]

2Alex Konshin © (01.05.03 10:44)
прошу прощение за вчерашний пост, ерунду какуюто написал, сорри


 
Nigger   (2003-05-05 07:27) [31]

Вообщим подведу итог для себя и для тех кому данная проблема интересна, поправьте если что-то не то сказал....
1) Компоненты Client\ServerSocket или TCPClient\Server - работают медленно и в некоторых случиях некорректно, так что рекомендуется использовать WinSockets.
2) Легче использовать вместо TThread асинхронное подключение.
3) Лучше сразу повешаться, чем все это понять.

Спасибо Alex Konshin, Polevi, Digitman, Illusion за продолжительную дисскусию и исчерпывающие ответы на всю эту тему...
Мне этой информации будет вполне достаточно, чтобы закончить написание этой ....ной программы просто пока времени не было с этим разбираться (в другой город ездил)...
И ещё один маленький вопрос на последок про функции RecvFrom
и SendTo: эти функции получают и отправляют информацию по заданному сокету???? То есть можно например все таки сделать несколько потоков и в них поместить эти функции(если они конечно, для заданного сокета)??? Или спрашиваю еще проще можно например с функцией RecvFrom получить данные с разных сокетов в разных нитях и в один и тот же момент??? или я сильно показалось..... перекрестюсь на всякий случай....


 
nikkie   (2003-05-05 13:46) [32]

>1) Компоненты Client\ServerSocket или TCPClient\Server - работают медленно и в некоторых случиях некорректно, так что рекомендуется использовать WinSockets

Здрасьте... Это кто ж такое говорил-то? Ты изначально задал вопрос про recv() задал, про компоненты никто и речи не было.

>2) Легче использовать вместо TThread асинхронное подключение.

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

Я пробовал писать программы с использованием как стандартных компонент, так и компонент ICS. Потом услышал о библиотеке Winshoes и, попробовав ее, окончательно переключился на нее. Через некоторое время ее переименовали в Indy. Очень доходчивое описание плюсов блокирующих сокетов (а также откуда взялись асинхронные сокеты на windows :)) можно прочитать в статье Chad Z. Hower (Kudzu) "Introduction to Indy".

http://www.swissdelphicenter.ch/en/showarticle.php?id=4


 
Nigger   (2003-05-05 14:10) [33]

2 nikkie: хмм....спасибо за ссылку... я буду использовать все методы, включая этот пока не найду оптимальный.



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

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

Наверх





Память: 0.57 MB
Время: 0.011 c
3-31088
Леха
2003-06-16 13:04
2003.07.10
Люди! Можно ли из грида всю инфу сохранить в файл в формат Excel?


14-31501
Леприкон
2003-06-23 07:58
2003.07.10
Как стать супер-пупер программистом?


1-31189
Tom
2003-06-27 20:23
2003.07.10
Как програмным путем добавить песню в Winamp?


1-31305
Zn
2003-06-26 15:22
2003.07.10
Как узнать, существует ли элемент?


1-31339
Bless
2003-06-26 10:59
2003.07.10
Поменять область видимости метода





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский