-
Добрый вечер, ув. Мастера! Помогите разобраться вот в чем. Я нашел одну статью по сокетам и оттуда взял готовые кусочки кода для сервера и клиента. Вот они: Код сервера:
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);
Код клиента:
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));
Проблема в том, что локально (на одном компе) этот код работает, а через ИНЕТ почему-то сервер не реагирует на входящий коннект, кагбутта ево нету :-( а клиент при попытке коннекта вроде как подключается, но видно, что НЕ ТУДА, КУДА НАДО. Может в коде что-то не так? Подскажите, кто чем может...
-
maxistent © (10.01.08 20:00) Connect функция, возвращающая результат. и не фукт что после вызова Connect произойдет "Теперь соединение установлено" - нет проверки... maxistent © (10.01.08 20:00) Я нашел одну статью по сокетам если в статье не описано как вызывать функции то это плохая статья... maxistent © (10.01.08 20:00) через ИНЕТ почему-то сервер не реагирует инет ничем не отличается от локально, кроме фсяких искуственных барьеров, поднятых для безопасности
-
> maxistent © (10.01.08 20:00)
Чем готовые компоненты не угодили ?
-
> Slym © (11.01.08 04:28) [1]
Все необходимые проверки я ставил (брал из другого примера). От этого ничего не изменилось. Т.е. Клиент вроде подключается (причем, довольно долго), и в конце концов получается, что он подключился. Но я-то знаю, что никуда он не подключился :(
Про статью хочу сказать, что там есть инфа по поводу вызова функций и примеры. Поэтому я и воспользовался именно этой статьёй :)
И по поводу ИНЕТа. Если другими прогами коннектицо (использующими тот же T[Server/Client]Socket), коннект происходит и инфа передаёца! Вот поэтому я и обратился сюда за консультацией...
Самое интересное, что даже если я совершенно "ЛЕВЫЙ" ИП укажу клиенту, то он всё-равно "подключается". Что за хрень такая? Как быть? Может действительно СЕРЬЁЗНЫЕ проверки нужны? Есть у кого-нить пример таких проверок? Это одно, и второе: почему же всё-таки к реально существующему серваку в ИНЕТе не коннектица?
> Сергей М. © (11.01.08 08:07) [2]
не угодили :) слишком много "напихано"...не нужного мне. всё, что мне нужно, это: от сервера: коннект (максимум до двух клиентов), дисконнект, read, write. от клиента: коннект, дисконнект, read, write. так что не ругайте меня за попытку изобретения велосипеда :) мне действительно нужно ИМЕННО ТАК.
-
> maxistent © (11.01.08 14:08) [3]
С учетом твоих претензий к TThread вырисовывается печальная картина твоего неумения читать и анализировать код)
И не надо уже маскировать этот факт под "слишком много напихано .. не нужного мне")
> если я совершенно "ЛЕВЫЙ" ИП укажу клиенту, то он всё-равно > "подключается"
Что, прямо так и говорит - "я подключился" ?)
> Есть у кого-нить пример таких проверок?
Ты вообще хотя бы справку удосужился полистать-поштудировать, прежде чем код клянчить ?)
Или в справке тоже "слишком много напихано .. не нужного мне" ?)
-
В справке ПРИМЕРЫ редко встречаются. а мне нужны именно примеры, т.к. на примере мне легче понять и переделать под свою задачу (если, конечно, он мне подходит). Если бы все читали справку, ЭТИХ форумов (да и любых других) не было бы наверно...
По поводу TThread: я его не стал использовать не потому, что не умею код анализировать, или там... звезды встали раком... или ещё что-то :) там действительно много того, что мне совершенно не нужно. и при подключении модуля с этим TThread размер проги увеличивается. это тоже неприятно :( тем более, я уже нашел решение той задачи с потоками.
По поводу "я подключился": я не знаю, что НА САМОМ ДЕЛЕ там происходит, но учитывая все необходимые проверки и отсутствие ошибок при коннекте этот коннект устанавливается. Похоже, что код неверный :( я уже не знаю, что и думать...
-
> мне нужны именно примеры
Там ведь, в примерах тех самых, буковки нерусские) ..
И в справке тоже нерусские)
В чем разница-то ?)
> По поводу "я подключился": я не знаю, что НА САМОМ ДЕЛЕ > там происходит
Ну так а какого ж лешего ты утверждаешь что подключился ?)
Вот тебе фрагмент справки, ищи знакомые букаффки:
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.
Нашел ?)
-
нашОл :(
> 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
-
хм... странно... понаставил кругом проверок и всё заработало. если коннект НА САМОМ ДЕЛЕ есть - то пишет "коннектед", если нет - "коннекшн еррор". в чем же была проблема? неужели в проверках на наличие ошибок?!
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);
-
Мда...
-
...единственное, что мне всё ещё не понятно, это как поймать момент дисконнекта? насколько я понимаю, инициатор должен сделать
ShutDown(socket,SD_BOTH);
CloseSocket(socket);
А что нужно сделать на другом конце "провода", чтобы об этом узнать?
-
> как поймать момент дисконнекта?
Ты еще момент коннекта на стороне его инициатора не ущучил, а уже о дисконнекте у партнера по коннекту рассуждаешь)
> что нужно сделать на другом конце "провода"
Можно вообще ничего не делать. А нахрена соббсно что-то делать ?
-
Я ж сказал: КОННЕКТ Я НАУЧИЛСЯ ДЕЛАТЬ. А вот как например клиенту узнать что сервер его "БРОСИЛ"? а серверу - что клиент отключился (или связь оборвалась)? Т.е. если я делаю на одной стороне ShutDown и CloseSocket, на другой стороне что должно произойти? Как этот момент отловить?
> А нахрена соббсно что-то делать ?
Чтобы знать, что коннекта больше нету и ничего не слать "ТУДА" и не ждать "ОТТУДА". Думаю, вполне логично :)
-
> КОННЕКТ Я НАУЧИЛСЯ ДЕЛАТЬ
Судя по вышеприведенному тобой коду, нихрена ты не научился.
Читай [1] до полного просветления.
connect() есть функция, какого же лешего ты используешь ее как процедуру ?
-
Уважаемый Сергей М. !!! В третий раз повторяю: с коннектом я разобрался, во всяком случае, я получил то, что было нужно. Принимать и отправлять данные я тоже умею. Остался один вопрос, и я его уже "озвучил". Если Вы не знаете ответа, или знаете, но не хотите отвечать - дело ваше. Просто молчите и фсьо! Функцию CONNECT в [8] я, как видите, не "обидел". Да и дело даже не в этом... Как я её использую - дело десятое. Главное, чтобы работало. А работает почти фсьо. Кроме дисконнекта. :-/
-
> maxistent © (12.01.08 01:16) [14]
В блокирующем режиме - а ты именно его используешь - узнать о дисконнекте можно, например, с пом. ф-ции select() или по результату вызова send() или recv()
-
> слишком много "напихано"
Это в TTCPClient/Server понапихано ?!
Аскетичней (безо всяких излишеств) и надежней компонентов чем эти еще поискать надо .
-
> с пом. ф-ции select()
с это функцией я ещё не разобрался...
> по результату вызова send() или recv()
хм... Пока коннект не установлен, вызов ф-ии recv() возвращает -1. После успешного коннекта вызов ф-ии recv() возвращает 0 (ну, если данные не идут ОТТУДА). Так и должно быть, наскока я понимаю. НО И ПОСЛЕ ДИСКОННЕКТА эта функция возвращает 0, и WSAGetLastError=0 <=-о Как быть? Это глюк?
-
> с это функцией я ещё не разобрался
Как раз есть повод.
> Это глюк?
Нет, это нормальное поведение функции.
-
> Slym © (11.01.08 04:28) [1] > > Я нашел одну статью по сокетам > если в статье не описано как вызывать функции то это плохая > статья...
Так как речь идёт о моей статье, приходится оправдываться :)
Сразу после процитированного в [0] кода там написано:
> В приведённом выше коде для краткости опущены проверки результатов > функций с целью обнаружения ошибок. При написании серьёзных > программ этим пренебрегать нельзя.
А проверки в таких примерах я опускал по одной причине: это не готовые примеры, а иллюстрации последовательности вызова сокетных функций для получения нужного результата. Есои проверять ошибки, то вызов каждой функции будет "обёрнут" в четыре-пять, если не больше, строчек, которые будут мешать разглядеть последовательность вызова и раздувать пример. Ко всем остальным примерам в статье следует относится так же. Вот, для примера, что там написано после другого листинга:
> Как и предыдущих примерах, код для краткости не содержит > проверок успешности завершения функций. Ещё раз напоминаю, > что в реальном коде такие проверки необходимы.
-
Григорьев Антон © (14.01.08 9:18) [19] Пример - он на то и пример: "Делай так и будет работать". А все что иначе не пример, а никчему не обязывающая демонстрация работы CTRL+V P.S. Дайте хоть ссылку на статью, а то хаю неведомо что :)
-
-
Григорьев Антон © (14.01.08 9:18) [19] А проверки в таких примерах я опускал как в сексе: сначала научись предохраняться - пользоваться призервативом, а уж потом учи матчасть применения "девайса" Connect("Девушка") Write("Туды") Read("Сюды") Close("Девушка")
Григорьев Антон © (14.01.08 9:18) [19] это не готовые примеры, а иллюстрации последовательности вызова сокетных функций для получения нужного результататыды надо пЕсать что это псевдокод и компиляции не подлежит... (как приведено выше :) )
-
Статья нормальная. Но желательно было бы в конце пару-тройку примеров приводить :-) Тада п ей ваще небыло п цены :-) Я по ней почти всё сделал. Вот только с "чтением" данных не могу разобрацо... Я сделал отдельный поток для 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;
-
> maxistent © (14.01.08 16:50) [23]
Ты бы к Кетмарю обратился - он знает куда тебе, твентинейджеру, податься.
-
???
-
> maxistent © (14.01.08 16:50) [23] > Статья нормальная. Но желательно было бы в конце пару-тройку > примеров приводить :-)
Примеры скоро будут, только немного в другом месте. Где-то в конце января - начале февраля должна выйти моя книга, в которую вошла и эта статья, в доработанном виде. Там к ней прилагается полностью рабочих 11 примеров, которые уже написаны без всяких упрощений, т.е. со всеми полагающимися проверками и обработками ошибок. Там есть и однонитевые, и многонитевые серверы.
> ...Вот тут я незнаю что сделать...
Что-то как-то я не понял, что именно вызывает затруднения. Что именно вы не знаете как сделать?
-
Я "сохраняю" входящий поток данных в массив <Buffer:array of char>. Теперь мне нужно написать обработчик, который смог бы сделать что-то вроде
ClientSocket1.Socket.ReceiveBuf();
точнее, написать функцию ReceiveBuf для своей конкретной задачи:
Function ReceiveBuf(var buf; BufSize:integer):integer;
begin
что здесь сделать,
чтобы в <Buf> скопировать <BufSize> байт из <Buffer>?
я не знаю, как преобразовать... :-(
end;
-
p.s. Как-то даже не удобно... я почти ушел от темы...
-
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); приведет к фрагментации памяти и дальнейшему краху сервера
-
=-о О как!.. ясно... пасиб за замечания.
|