![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблемы с сокетами [D7, WinXP]
maxistent © (2008-01-10 20:00:00)Добрый вечер, ув. Мастера! Помогите разобраться вот в чем. Я нашел одну статью по сокетам и оттуда взял готовые кусочки кода для сервера и клиента. Вот они:
Код сервера:
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,…) - получить данные от сервера }
Проблема в том, что локально (на одном компе) этот код работает, а через ИНЕТ почему-то сервер не реагирует на входящий коннект, кагбутта ево нету :-( а клиент при попытке коннекта вроде как подключается, но видно, что НЕ ТУДА, КУДА НАДО. Может в коде что-то не так? Подскажите, кто чем может...
maxistent (2008-01-15 06:17:00) [1]=-о О как!.. ясно... пасиб за замечания.
Slym (2008-01-15 04:14:00) [2]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-14 17:55:00) [3]p.s. Как-то даже не удобно... я почти ушел от темы...
maxistent (2008-01-14 17:53:00) [4]Я "сохраняю" входящий поток данных в массив <Buffer:array of char>. Теперь мне нужно написать обработчик, который смог бы сделать что-то вроде
ClientSocket1.Socket.ReceiveBuf();
точнее, написать функцию ReceiveBuf для своей конкретной задачи:
Function ReceiveBuf(var buf; BufSize:integer):integer;
begin
что здесь сделать,
чтобы в <Buf> скопировать <BufSize> байт из <Buffer>?
я не знаю, как преобразовать... :-(
end;
Григорьев Антон (2008-01-14 17:29:00) [5]
> maxistent © (14.01.08 16:50) [23]
> Статья нормальная. Но желательно было бы в конце пару-тройку
> примеров приводить :-)
Примеры скоро будут, только немного в другом месте. Где-то в конце января - начале февраля должна выйти моя книга, в которую вошла и эта статья, в доработанном виде. Там к ней прилагается полностью рабочих 11 примеров, которые уже написаны без всяких упрощений, т.е. со всеми полагающимися проверками и обработками ошибок. Там есть и однонитевые, и многонитевые серверы.
> ...Вот тут я незнаю что сделать...
Что-то как-то я не понял, что именно вызывает затруднения. Что именно вы не знаете как сделать?
maxistent (2008-01-14 17:20:00) [6]???
Сергей М. (2008-01-14 17:17:00) [7]
> maxistent © (14.01.08 16:50) [23]
Ты бы к Кетмарю обратился - он знает куда тебе, твентинейджеру, податься.
maxistent (2008-01-14 16:50:00) [8]Статья нормальная. Но желательно было бы в конце пару-тройку примеров приводить :-) Тада п ей ваще небыло п цены :-) Я по ней почти всё сделал. Вот только с "чтением" данных не могу разобрацо... Я сделал отдельный поток для 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;
Slym (2008-01-14 09:49:00) [9]Григорьев Антон © (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]
это не готовые примеры, а иллюстрации последовательности вызова сокетных функций для получения нужного результата
тыды надо пЕсать что это псевдокод и компиляции не подлежит... (как приведено выше :) )
Григорьев Антон (2008-01-14 09:38:00) [10]
> Slym © (14.01.08 09:36) [20]
> P.S. Дайте хоть ссылку на статью, а то хаю неведомо что
> :)
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1021
Slym (2008-01-14 09:36:00) [11]Григорьев Антон © (14.01.08 9:18) [19]
Пример - он на то и пример: "Делай так и будет работать".
А все что иначе не пример, а никчему не обязывающая демонстрация работы CTRL+V
P.S. Дайте хоть ссылку на статью, а то хаю неведомо что :)
Григорьев Антон (2008-01-14 09:18:00) [12]
> Slym © (11.01.08 04:28) [1]
> > Я нашел одну статью по сокетам
> если в статье не описано как вызывать функции то это плохая
> статья...
Так как речь идёт о моей статье, приходится оправдываться :)
Сразу после процитированного в [0] кода там написано:
> В приведённом выше коде для краткости опущены проверки результатов
> функций с целью обнаружения ошибок. При написании серьёзных
> программ этим пренебрегать нельзя.
А проверки в таких примерах я опускал по одной причине: это не готовые примеры, а иллюстрации последовательности вызова сокетных функций для получения нужного результата. Есои проверять ошибки, то вызов каждой функции будет "обёрнут" в четыре-пять, если не больше, строчек, которые будут мешать разглядеть последовательность вызова и раздувать пример. Ко всем остальным примерам в статье следует относится так же. Вот, для примера, что там написано после другого листинга:
> Как и предыдущих примерах, код для краткости не содержит
> проверок успешности завершения функций. Ещё раз напоминаю,
> что в реальном коде такие проверки необходимы.
Сергей М. (2008-01-12 18:13:00) [13]
> с это функцией я ещё не разобрался
Как раз есть повод.
> Это глюк?
Нет, это нормальное поведение функции.
maxistent (2008-01-12 18:04:00) [14]
> с пом. ф-ции select()
с это функцией я ещё не разобрался...
> по результату вызова send() или recv()
хм... Пока коннект не установлен, вызов ф-ии recv() возвращает -1. После успешного коннекта вызов ф-ии recv() возвращает 0 (ну, если данные не идут ОТТУДА). Так и должно быть, наскока я понимаю. НО И ПОСЛЕ ДИСКОННЕКТА эта функция возвращает 0, и WSAGetLastError=0 <=-о Как быть? Это глюк?
Сергей М. (2008-01-12 17:06:00) [15]
> слишком много "напихано"
Это в TTCPClient/Server понапихано ?!
Аскетичней (безо всяких излишеств) и надежней компонентов чем эти еще поискать надо .
Сергей М. (2008-01-12 15:34:00) [16]
> maxistent © (12.01.08 01:16) [14]
В блокирующем режиме - а ты именно его используешь - узнать о дисконнекте можно, например, с пом. ф-ции select() или по результату вызова send() или recv()
maxistent (2008-01-12 01:16:00) [17]Уважаемый Сергей М. !!! В третий раз повторяю: с коннектом я разобрался, во всяком случае, я получил то, что было нужно. Принимать и отправлять данные я тоже умею. Остался один вопрос, и я его уже "озвучил". Если Вы не знаете ответа, или знаете, но не хотите отвечать - дело ваше. Просто молчите и фсьо! Функцию CONNECT в [8] я, как видите, не "обидел". Да и дело даже не в этом... Как я её использую - дело десятое. Главное, чтобы работало. А работает почти фсьо. Кроме дисконнекта. :-/
Сергей М. (2008-01-11 23:37:00) [18]
> КОННЕКТ Я НАУЧИЛСЯ ДЕЛАТЬ
Судя по вышеприведенному тобой коду, нихрена ты не научился.
Читай [1] до полного просветления.
connect() есть функция, какого же лешего ты используешь ее как процедуру ?
maxistent (2008-01-11 23:17:00) [19]Я ж сказал: КОННЕКТ Я НАУЧИЛСЯ ДЕЛАТЬ. А вот как например клиенту узнать что сервер его "БРОСИЛ"? а серверу - что клиент отключился (или связь оборвалась)? Т.е. если я делаю на одной стороне ShutDown и CloseSocket, на другой стороне что должно произойти? Как этот момент отловить?
> А нахрена соббсно что-то делать ?
Чтобы знать, что коннекта больше нету и ничего не слать "ТУДА" и не ждать "ОТТУДА". Думаю, вполне логично :)
Сергей М. (2008-01-11 22:22:00) [20]
> как поймать момент дисконнекта?
Ты еще момент коннекта на стороне его инициатора не ущучил, а уже о дисконнекте у партнера по коннекту рассуждаешь)
> что нужно сделать на другом конце "провода"
Можно вообще ничего не делать.
А нахрена соббсно что-то делать ?