Конференция "Сети" » Проблемы с сокетами [D7, WinXP]
 
  • maxistent © (10.01.08 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 © (11.01.08 04:28) [1]
    maxistent ©   (10.01.08 20:00)
    Connect

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

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

    инет ничем не отличается от локально, кроме фсяких искуственных барьеров, поднятых для безопасности
  • Сергей М. © (11.01.08 08:07) [2]

    > maxistent ©   (10.01.08 20:00)


    Чем готовые компоненты не угодили ?
  • maxistent © (11.01.08 14:08) [3]

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


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

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

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

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


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

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

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


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

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


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


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


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


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

    Или в справке тоже "слишком много напихано .. не нужного мне" ?)
  • maxistent © (11.01.08 15:36) [5]
    В справке ПРИМЕРЫ редко встречаются. а мне нужны именно примеры, т.к. на примере мне легче понять и переделать под свою задачу (если, конечно, он мне подходит). Если бы все читали справку, ЭТИХ форумов (да и любых других) не было бы наверно...

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

    По поводу "я подключился": я не знаю, что НА САМОМ ДЕЛЕ там происходит, но учитывая все необходимые проверки и отсутствие ошибок при коннекте этот коннект устанавливается. Похоже, что код неверный :( я уже не знаю, что и думать...
  • Сергей М. © (11.01.08 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 © (11.01.08 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 © (11.01.08 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);

  • Сергей М. © (11.01.08 19:42) [9]
    Мда...
  • maxistent © (11.01.08 21:53) [10]
    ...единственное, что мне всё ещё не понятно, это как поймать момент дисконнекта? насколько я понимаю, инициатор должен сделать

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


    А что нужно сделать на другом конце "провода", чтобы об этом узнать?
  • Сергей М. © (11.01.08 22:22) [11]

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


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


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


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

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

    Чтобы знать, что коннекта больше нету и ничего не слать "ТУДА" и не ждать "ОТТУДА". Думаю, вполне логично :)
  • Сергей М. © (11.01.08 23:37) [13]

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


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

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

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

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


    В блокирующем режиме - а ты именно его используешь - узнать о дисконнекте можно, например, с пом. ф-ции select() или по результату вызова send() или recv()
  • Сергей М. © (12.01.08 17:06) [16]

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


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

    Аскетичней (безо всяких излишеств) и надежней компонентов чем эти еще поискать надо .
  • maxistent © (12.01.08 18:04) [17]

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

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

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

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

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


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


    > Это глюк?


    Нет, это нормальное поведение функции.
  • Григорьев Антон © (14.01.08 09:18) [19]

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

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

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

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

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

    > Как и предыдущих примерах, код для краткости не содержит
    > проверок успешности завершения функций. Ещё раз напоминаю,
    >  что в реальном коде такие проверки необходимы.
  • Slym © (14.01.08 09:36) [20]
    Григорьев Антон ©   (14.01.08 9:18) [19]
    Пример - он на то и пример: "Делай так и будет работать".
    А все что иначе не пример, а никчему не обязывающая демонстрация работы CTRL+V
    P.S. Дайте хоть ссылку на статью, а то хаю неведомо что :)
  • Григорьев Антон © (14.01.08 09:38) [21]

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

    http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1021
  • Slym © (14.01.08 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 © (14.01.08 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;

  • Сергей М. © (14.01.08 17:17) [24]

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


    Ты бы к Кетмарю обратился - он знает куда тебе, твентинейджеру, податься.
  • maxistent © (14.01.08 17:20) [25]
    ???
  • Григорьев Антон © (14.01.08 17:29) [26]

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

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

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

    Что-то как-то я не понял, что именно вызывает затруднения. Что именно вы не знаете как сделать?
  • maxistent © (14.01.08 17:53) [27]
    Я "сохраняю" входящий поток данных в массив <Buffer:array of char>. Теперь мне нужно написать обработчик, который смог бы сделать что-то вроде

    ClientSocket1.Socket.ReceiveBuf();


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

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

  • maxistent © (14.01.08 17:55) [28]
    p.s. Как-то даже не удобно... я почти ушел от темы...
  • Slym © (15.01.08 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 © (15.01.08 06:17) [30]
    =-о  О как!.. ясно... пасиб за замечания.
 
Конференция "Сети" » Проблемы с сокетами [D7, WinXP]
Есть новые Нет новых   [134431   +15][b:0][p:0.003]