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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.047 c
15-1232089317
Slider007
2009-01-16 10:01
2009.03.15
С днем рождения ! 16 января 2009 пятница


6-1199882403
DmitriyG.
2008-01-09 15:40
2009.03.15
Dump IP сообщения


15-1231753699
NailMan
2009-01-12 12:48
2009.03.15
немного про свои сайты


2-1232454943
аврам
2009-01-20 15:35
2009.03.15
http gzip


15-1231596252
Slider007
2009-01-10 17:04
2009.03.15
С днем рождения ! 4 января 2009 воскресенье





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