Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.03.15;
Скачать: CL | DM;

Вниз

Проблемы с сокетами   Найти похожие ветки 

 
maxistent ©   (2008-01-10 20:00) [0]

Добрый вечер, ув. Мастера! Помогите разобраться вот в чем. Я нашел одну статью по сокетам и оттуда взял готовые кусочки кода для сервера и клиента. Вот они:
Код сервера:

var S,AcceptedSock:TSocket;
   Addr:TSockAddr;
   Data:TWSAData;
   Len:Integer;
begin
 WSAStartup($101,Data);
 S:=Socket(AF_Inet,Sock_Stream,0);
 Addr.sin_family:=PF_Inet;
 Addr.sin_port:=HToNS(1234);
 Addr.sin_addr.S_addr:=InAddr_Any;
 FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0);
 Bind(S,Addr,SizeOf(TSockAddr));
 Listen(S,SoMaxConn);
 Len:=SizeOf(TSockAddr);
 AcceptedSock:=Accept(S,@Addr,@Len);
 { Теперь Addr содержит адрес клиента, с которым установлено
   соединение, а AcceptedSock - дескриптор, обслуживающий это
   соединение. Допустимы следующие действия:
    Send(AcceptedSock,…) - отправить данные клиенту
    Recv(AcceptedSock,…) - получить данные от клиента
    Accept(…) - установить соединение с новым клиентом }


Код клиента:

var S:TSocket;
   Addr:TSockAddr;
   Data:TWSAData;
begin
 WSAStartup($101,Data);
 S:=Socket(AF_Inet,Sock_Stream,0);
 Addr.sin_family:=AF_Inet;
 Addr.sin_port:=HToNS(1234);
 Addr.sin_addr.S_addr:=Inet_Addr("127.0.0.1");
 FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0);
 Connect(S,Addr,SizeOf(TSockAddr));
 { Теперь соединение установлено. Допустимы следующие действия:
    Send(S,…) - отправить данные серверу
    Recv(S,…) - получить данные от сервера }

Проблема в том, что локально (на одном компе) этот код работает, а через ИНЕТ почему-то сервер не реагирует на входящий коннект, кагбутта ево нету :-( а клиент при попытке коннекта вроде как подключается, но видно, что НЕ ТУДА, КУДА НАДО. Может в коде что-то не так? Подскажите, кто чем может...


 
Slym ©   (2008-01-11 04:28) [1]

maxistent ©   (10.01.08 20:00)
Connect

функция, возвращающая результат. и не фукт что после вызова Connect произойдет "Теперь соединение установлено" - нет проверки...
maxistent ©   (10.01.08 20:00)
Я нашел одну статью по сокетам

если в статье не описано как вызывать функции то это плохая статья...
maxistent ©   (10.01.08 20:00)
через ИНЕТ почему-то сервер не реагирует

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


 
Сергей М. ©   (2008-01-11 08:07) [2]


> maxistent ©   (10.01.08 20:00)


Чем готовые компоненты не угодили ?


 
maxistent ©   (2008-01-11 14:08) [3]


> Slym ©   (11.01.08 04:28) [1]


Все необходимые проверки я ставил (брал из другого примера). От этого ничего не изменилось. Т.е. Клиент вроде подключается (причем, довольно долго), и в конце концов получается, что он подключился. Но я-то знаю, что никуда он не подключился :(

Про статью хочу сказать, что там есть инфа по поводу вызова функций и примеры. Поэтому я и воспользовался именно этой статьёй :)

И по поводу ИНЕТа. Если другими прогами коннектицо (использующими тот же T[Server/Client]Socket), коннект происходит и инфа передаёца! Вот поэтому я и обратился сюда за консультацией...

Самое интересное, что даже если я совершенно "ЛЕВЫЙ" ИП укажу клиенту, то он всё-равно "подключается". Что за хрень такая? Как быть? Может действительно СЕРЬЁЗНЫЕ проверки нужны? Есть у кого-нить пример таких проверок? Это одно, и второе: почему же всё-таки к реально существующему серваку в ИНЕТе не коннектица?


> Сергей М. ©   (11.01.08 08:07) [2]

не угодили :) слишком много "напихано"...не нужного мне. всё, что мне нужно, это:
от сервера: коннект (максимум до двух клиентов), дисконнект, read, write.
от клиента: коннект, дисконнект, read, write.
так что не ругайте меня за попытку изобретения велосипеда :) мне действительно нужно ИМЕННО ТАК.


 
Сергей М. ©   (2008-01-11 14:15) [4]


> maxistent ©   (11.01.08 14:08) [3]


С учетом твоих претензий к TThread вырисовывается печальная картина твоего неумения читать и анализировать код)

И не надо уже маскировать этот факт под "слишком много напихано .. не нужного мне")


> если я совершенно "ЛЕВЫЙ" ИП укажу клиенту, то он всё-равно
> "подключается"


Что, прямо так и говорит - "я подключился" ?)


> Есть у кого-нить пример таких проверок?


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

Или в справке тоже "слишком много напихано .. не нужного мне" ?)


 
maxistent ©   (2008-01-11 15:36) [5]

В справке ПРИМЕРЫ редко встречаются. а мне нужны именно примеры, т.к. на примере мне легче понять и переделать под свою задачу (если, конечно, он мне подходит). Если бы все читали справку, ЭТИХ форумов (да и любых других) не было бы наверно...

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

По поводу "я подключился": я не знаю, что НА САМОМ ДЕЛЕ там происходит, но учитывая все необходимые проверки и отсутствие ошибок при коннекте этот коннект устанавливается. Похоже, что код неверный :( я уже не знаю, что и думать...


 
Сергей М. ©   (2008-01-11 15:49) [6]


> мне нужны именно примеры


Там ведь, в примерах тех самых, буковки нерусские) ..

И в справке тоже нерусские)

В чем разница-то ?)


> По поводу "я подключился": я не знаю, что НА САМОМ ДЕЛЕ
> там происходит


Ну так а какого ж лешего ты утверждаешь что подключился ?)

Вот тебе фрагмент справки, ищи знакомые букаффки:

Return Values

If no error occurs, connect returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.

Нашел ?)


 
maxistent ©   (2008-01-11 17:22) [7]

нашОл :(

> If no error occurs, connect returns zero. Otherwise, it returns SOCKET_ERROR,
> and a specific error code can be retrieved by calling WSAGetLastError.

Вот именно в соответствии с этим я и делаю вывод о том, что коннект произошел, т.е. результ=0 (ноу еррорс).  =-o


 
maxistent ©   (2008-01-11 17:55) [8]

хм... странно... понаставил кругом проверок и всё заработало. если коннект НА САМОМ ДЕЛЕ есть - то пишет "коннектед", если нет - "коннекшн еррор". в чем же была проблема? неужели в проверках на наличие ошибок?!


WsaErr := WSAStartUp($101, Data);
if WsaErr <> 0 then
begin
writeln("WSA error");
readln;
exit;
end;

with Addr do
begin
sin_family := AF_INET;
sin_port := htons(1234);
sin_addr.S_addr := Inet_Addr("123.123.123.123");
end;

S := socket(AF_INET, SOCK_STREAM, 0);
if S = INVALID_SOCKET then
begin
writeln("Socket error");
readln;
exit;
end;
if Connect(S, Addr, SizeOf(Addr)) <> 0 then
begin
writeln("Connection error");
readln;
exit;
end;


Вот тут я уже точно знаю, есть коннект или нет. Странно... Ну и ладно, главное РАБОТАЕТ! Всем спасибо. Особенно Сергею М.! :)

FreeMem(maxistent);


 
Сергей М. ©   (2008-01-11 19:42) [9]

Мда...


 
maxistent ©   (2008-01-11 21:53) [10]

...единственное, что мне всё ещё не понятно, это как поймать момент дисконнекта? насколько я понимаю, инициатор должен сделать

ShutDown(socket,SD_BOTH);
CloseSocket(socket);

А что нужно сделать на другом конце "провода", чтобы об этом узнать?


 
Сергей М. ©   (2008-01-11 22:22) [11]


> как поймать момент дисконнекта?


Ты еще момент коннекта на стороне его инициатора не ущучил, а уже о дисконнекте у партнера по коннекту рассуждаешь)


> что нужно сделать на другом конце "провода"


Можно вообще ничего не делать.
А нахрена соббсно что-то делать ?


 
maxistent ©   (2008-01-11 23:17) [12]

Я ж сказал: КОННЕКТ Я НАУЧИЛСЯ ДЕЛАТЬ. А вот как например клиенту узнать что сервер его "БРОСИЛ"? а серверу - что клиент отключился (или связь оборвалась)? Т.е. если я делаю на одной стороне ShutDown и CloseSocket, на другой стороне что должно произойти? Как этот момент отловить?

> А нахрена соббсно что-то делать ?

Чтобы знать, что коннекта больше нету и ничего не слать "ТУДА" и не ждать "ОТТУДА". Думаю, вполне логично :)


 
Сергей М. ©   (2008-01-11 23:37) [13]


> КОННЕКТ Я НАУЧИЛСЯ ДЕЛАТЬ


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

Читай [1] до полного просветления.

connect() есть функция, какого же лешего ты используешь ее как процедуру ?


 
maxistent ©   (2008-01-12 01:16) [14]

Уважаемый Сергей М. !!! В третий раз повторяю: с коннектом я разобрался, во всяком случае, я получил то, что было нужно. Принимать и отправлять данные я тоже умею. Остался один вопрос, и я его уже "озвучил". Если Вы не знаете ответа, или знаете, но не хотите отвечать - дело ваше. Просто молчите и фсьо! Функцию CONNECT в [8] я, как видите, не "обидел". Да и дело даже не в этом... Как я её использую - дело десятое. Главное, чтобы работало. А работает почти фсьо. Кроме дисконнекта. :-/


 
Сергей М. ©   (2008-01-12 15:34) [15]


> maxistent ©   (12.01.08 01:16) [14]


В блокирующем режиме - а ты именно его используешь - узнать о дисконнекте можно, например, с пом. ф-ции select() или по результату вызова send() или recv()


 
Сергей М. ©   (2008-01-12 17:06) [16]


> слишком много "напихано"


Это в TTCPClient/Server понапихано ?!

Аскетичней (безо всяких излишеств) и надежней компонентов чем эти еще поискать надо .


 
maxistent ©   (2008-01-12 18:04) [17]


> с пом. ф-ции select()

с это функцией я ещё не разобрался...

> по результату вызова send() или recv()

хм... Пока коннект не установлен, вызов ф-ии recv() возвращает -1. После успешного коннекта вызов ф-ии recv() возвращает 0 (ну, если данные не идут ОТТУДА). Так и должно быть, наскока я понимаю. НО И ПОСЛЕ ДИСКОННЕКТА эта функция возвращает 0, и WSAGetLastError=0 <=-о Как быть? Это глюк?


 
Сергей М. ©   (2008-01-12 18:13) [18]


> с это функцией я ещё не разобрался


Как раз есть повод.


> Это глюк?


Нет, это нормальное поведение функции.


 
Григорьев Антон ©   (2008-01-14 09:18) [19]


> Slym ©   (11.01.08 04:28) [1]
> > Я нашел одну статью по сокетам
> если в статье не описано как вызывать функции то это плохая
> статья...

Так как речь идёт о моей статье, приходится оправдываться :)

Сразу после процитированного в [0] кода там написано:

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

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

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


 
Slym ©   (2008-01-14 09:36) [20]

Григорьев Антон ©   (14.01.08 9:18) [19]
Пример - он на то и пример: "Делай так и будет работать".
А все что иначе не пример, а никчему не обязывающая демонстрация работы CTRL+V
P.S. Дайте хоть ссылку на статью, а то хаю неведомо что :)


 
Григорьев Антон ©   (2008-01-14 09:38) [21]


> Slym ©   (14.01.08 09:36) [20]
> P.S. Дайте хоть ссылку на статью, а то хаю неведомо что
> :)

http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1021


 
Slym ©   (2008-01-14 09:49) [22]

Григорьев Антон ©   (14.01.08 9:18) [19]
А проверки в таких примерах я опускал

как в сексе: сначала научись предохраняться - пользоваться призервативом,
а уж потом учи матчасть применения "девайса"
Connect("Девушка")//нету проверки - девушка ли это?
Write("Туды")// raise Exception.Create("Не туда..:)")
Read("Сюды")// raise Exception.Create("Словили трепака")
Close("Девушка")// raise Exception.Create("через 9 месяцев Out of memory, Произошло рождение ошибки молодости")


Григорьев Антон ©   (14.01.08 9:18) [19]
это не готовые примеры, а иллюстрации последовательности вызова сокетных функций для получения нужного результата

тыды надо пЕсать что это псевдокод и компиляции не подлежит... (как приведено выше :) )


 
maxistent ©   (2008-01-14 16:50) [23]

Статья нормальная. Но желательно было бы в конце пару-тройку примеров приводить :-) Тада п ей ваще небыло п цены :-) Я по ней почти всё сделал. Вот только с "чтением" данных не могу разобрацо... Я сделал отдельный поток для recv() и там же определяю: если result<=0, то коннект, наскока я понимаю, пропал (выполняю необходимые действия). Если же result>0, то я делаю сохраняю данные в массив. Вот примерно так это выглядит:

x:=recv(FClientSocket,buf,BufSize,0);
if x>0 then
begin //Данные есть
inc(DataSize,x);
SetLength(MainBuffer,DataSize);
for i:=0 to x do
param.Buffer[param.DataSize-x+i]:=buf[i];
DoOnRead;
end
else
begin //Данных нету
DoOnDisconnect;
break;
end;

DoOnRead;
begin
//Здесь у меня есть
Buffer:array of char;
DataSize:integer;
Здесь нужно вызвать ещё одну процедуру обработки и передать в параметрах Buffer и DataSize.
end;

Procedure DoOnRead(var buf; BufSize:integer);
begin
if @OnClientRead<>nil then
begin
...Вот тут я незнаю что сделать...
??? OnClientRead(buf,BufSize); ???
end;
end;


 
Сергей М. ©   (2008-01-14 17:17) [24]


> maxistent ©   (14.01.08 16:50) [23]


Ты бы к Кетмарю обратился - он знает куда тебе, твентинейджеру, податься.


 
maxistent ©   (2008-01-14 17:20) [25]

???


 
Григорьев Антон ©   (2008-01-14 17:29) [26]


> maxistent ©   (14.01.08 16:50) [23]
> Статья нормальная. Но желательно было бы в конце пару-тройку
> примеров приводить :-)

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

> ...Вот тут я незнаю что сделать...

Что-то как-то я не понял, что именно вызывает затруднения. Что именно вы не знаете как сделать?


 
maxistent ©   (2008-01-14 17:53) [27]

Я "сохраняю" входящий поток данных в массив <Buffer:array of char>. Теперь мне нужно написать обработчик, который смог бы сделать что-то вроде

ClientSocket1.Socket.ReceiveBuf();

точнее, написать функцию ReceiveBuf для своей конкретной задачи:

Function ReceiveBuf(var buf; BufSize:integer):integer;
begin
что здесь сделать,
чтобы в <Buf> скопировать <BufSize> байт из <Buffer>?
я не знаю, как преобразовать... :-(
end;


 
maxistent ©   (2008-01-14 17:55) [28]

p.s. Как-то даже не удобно... я почти ушел от темы...


 
Slym ©   (2008-01-15 04:14) [29]

maxistent ©   (14.01.08 16:50) [23]
for i:=0 to x do
param.Buffer[param.DataSize-x+i]:=buf[i];

пипец...
зачем данные накапливаешь? всеравно каждый раз DoOnRead вызываешь в котором скорее всего буфер чистишь
maxistent ©   (14.01.08 16:50) [23]
передать в параметрах Buffer и DataSize

проблемы передать 2 параметра? если var buf; то передавать Buffer:array of char; нужно как Buffer[0]

и зачем весь этот гемор? твой самодельный сервер с кучей ошибок завалить будет проще пареной репы...
for i:=0 to x do
for i:=0 to x do // принято х, а копируем x+1 раз....
т.е. теоретически посылая по 1 байту ты огребешь по 2 причинам:
1. переполнение буфера на 1 байт
2. SetLength(MainBuffer,1); приведет к фрагментации памяти и дальнейшему краху сервера


 
maxistent ©   (2008-01-15 06:17) [30]

=-о  О как!.. ясно... пасиб за замечания.



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

Текущий архив: 2009.03.15;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.02 c
2-1213617871
Layner
2008-06-16 16:04
2009.03.15
Как по "правильному" распарсить стр. дату "22/06/2008 08:54:04"


2-1232948305
charoey_mag
2009-01-26 08:38
2009.03.15
Скриншот Рабочего стола


6-1199991554
sdaf
2008-01-10 21:59
2009.03.15
отправка писем на емаил


2-1232628723
charoey_mag
2009-01-22 15:52
2009.03.15
Получить имя NetBIOS


15-1231941638
DillerXX
2009-01-14 17:00
2009.03.15
Подскажите про распределение нагрузок