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

Вниз

Несколько TClientSocket   Найти похожие ветки 

 
Новичоккк   (2006-05-31 10:27) [0]

Столкнулся с тем, что путаются ответы

Вот такой массив:
 aSock:array of record
    s:TClientSocket;
    r:TSRes;
    m:string;
    end;


Так инициализирую:

const THREADS=5
...
SetLength(aSock,THREADS);
for i:=0 to Length(aSock)-1 do
   begin
    aSock[i].s:=TClientSocket.Create(nil);
    with aSock[i].s do
       begin
        address:="xxx.xxx.xxx.xxx";
        port:=xxxx;
        clienttype:=ctNonBlocking;
        tag:=i;
        onRead:=aSockRead;
        onDisconnect:=aSockDisconnect;
       end;
    aSock[i].r:=lWRONG;
   end;

while not DONE do
   begin
     for i:=0 to Length(aSock)-1 do
         begin
          if DONE or (aSock[i].r=lBF) then
             begin
              AddInfo("----- Stop Threads -----",clBlue,"["+IntToStr(i)+"] ",clPurple);
              break;
             end;
          if aSock[i].r=lWRONG then
             begin
              aSock[i].m:=GenNewMessage;
              aSock[i].r:=lWAIT;
              aSock[i].s.Active:=true;
             end;
          Application.ProcessMessages;
         end;
   end;


Обработчик события:
procedure TfrmMain.aSockRead(Sender: TObject; Socket: TCustomWinSocket);
var
str:string;
tag:integer;
begin
str:=Socket.ReceiveText;
tag:=(Sender as TClientSocket).Tag;
AddInfo(IntToStr(Length(str))+" bytes from server",clBlack,"["+IntToStr(tag)+"] ",clPurple);
if Length(str)=11 then
   begin
    AddInfo("-> 50 bytes",clBlack,"["+IntToStr(tag)+"] ",clPurple);
    socket.SendText(aSock[tag].m);
    exit;
   end;
if Length(str)=18 then
 begin
  AddInfo("WRONG: "+aSock[tag].p,clRed,"["+IntToStr(tag)+"] ",clPurple);
  aSock[tag].r:=lWRONG;
 end;
if Length(str)=50 then
 begin
  done:=true;
  AddInfo("OK: "+aSock[tag].p,clGreen,"["+IntToStr(tag)+"] ",clPurple);
  aSock[tag].r:=lOK;
 end;
aSock[tag].s.Active:=false;
aSock[tag].s.Close;
end;


Протокол общения:
Соединяемся с сервером, ждём приветствия 11 байт, посылаем серверу сообщение. Сервер отвечает либо 18 байт, либо 50 байт. Завершение сессии.

В итоге у меня сокеты получают свои персональные сообщения и общаются с сервером. В итоге каждому сообщению присваивается флаг 0 или 1 (по полученному ответу от сервера 18 или 50 байт).

Так вот в чем проблема - ответы путаются. Уже вторые сутки пытаюсь разобраться почему возникают коллизии?
Я конечно понимаю, что информации много. Но очень надеюсь, что кто-нибудь из мастеров уделит мне несколько минут и поможет решить проблему.


 
Сергей М. ©   (2006-05-31 10:33) [1]


> if Length(str)=11 then
> if Length(str)=18 then
> if Length(str)=50 then


Ни одно из этих условий не обязано выполняться.


 
Новичоккк   (2006-05-31 10:39) [2]


> Ни одно из этих условий не обязано выполняться.

В моём случае выполняется всегда. А даже если и произойдет уникальное событие - сокет просто закрывается.


 
Сергей М. ©   (2006-05-31 10:57) [3]


> В моём случае выполняется всегда


Как только разнесешь свои клиент и сервер на разные хосты разных подсетей в глоб.сети, эта "железная логика" тут же потерпит крах.


 
Новичоккк   (2006-05-31 11:12) [4]

Буду знать... Но сейчас это вопрос второстепенный... Почему сокеты получают чужие ответы?


 
Сергей М. ©   (2006-05-31 11:27) [5]


> Почему сокеты получают чужие ответы?


Сокет не может получать "чужие ответы" - он получает ответ именно от того сервера, с которым был установлен коннект.


 
Новичоккк   (2006-05-31 12:05) [6]

Сервер один и тот же. Несколько сокетов соединяются с одним сервером. Обработчик onRead общий (код в первом посте).

Что в итоге получается (упрощенный вариант)
1. Сокету S0 назначается сообщение "0". Активация сокета.
2. Сокету S1 назначается сообщение "1". Активация сокета.
3. Сокету S2 назначается сообщение "2". Активация сокета.
Я знаю, что на сообщение "1" сервер должен дать ответ OK, на сообщения "0" и "2" ответ ERROR.
Т.е. S0 и S2 должны принять ERROR, S1 - OK.

А в итоге, этот ответ OK попадает случайным образом или к S0, или к S1, или к S2. Почему там происходит - я не могу разобраться уже второй день.
Код выше. Надеюсь на вашу помощь.


 
Новичоккк   (2006-05-31 12:14) [7]

Плюс ответ ОК может придти двум или даже всем сокетам S0-S2, а может вообще ни кому не поступить (S0-S2 получат ответ ERROR).


 
Сергей М. ©   (2006-05-31 12:23) [8]

Неплохо было бы на код сервера взглянуть ..


 
Новичоккк   (2006-05-31 12:28) [9]

Сервер 100% работает правильно
Если сделать один поток в клиенте (THREADS=1 в примере), то все ответы приходят правильно (все OK на нужные сообщения и все ERROR на остальные)


 
Сергей М. ©   (2006-05-31 12:33) [10]


> Если сделать один поток в клиенте (THREADS=1 в примере),


В примере я не вижу никаких потоков...


 
Новичоккк   (2006-05-31 12:37) [11]

Ну не потоки... сокеты

aSock - массив сокетов (плюс текущий статус и сообщение в каждом элементе массива)
Все они ctNonBlocking


 
Сергей М. ©   (2006-05-31 12:56) [12]

Мне не понятен смысл, заложенный в протоколе.


> Сокету S0 назначается сообщение "0"


Сообщение клиента серверу, содержащее строку из одного символа, это реальное сообщение в соответствии с протоколом или просто некий пример ?


 
Новичоккк   (2006-05-31 13:08) [13]

Упрощенный пример. Реальный протокол:
1. Соединение
2. Сервер посылает приветствие 11 байт
3. Клиент посылает серверу пакет, содержащий несколько полей (пакет 50 байт). Поля - операнды...
4. Сервер выполняет над полями некоторые операции и высылает ответ. Два типа ответа - 18 байт и 50 байт. В данном случае содержимое ответов не важно - главное длина ответа. В соответствии с чем устанавливается флаг (0 или 1, OK или ERROR).
5. Разъединение

Чтобы ускорить проверку, я создаю массив сокетов. В итоге ответ из пунтка 4 путается (его может получить случайный сокет). Как факт - на свой запрос, сокет получает ответ, предназначенный для другого сокета из массива.
Если массив будет состоять всего лишь из одного сокета (THREADS=1), то на все запросы приходят правильные ответы.


 
Сергей М. ©   (2006-05-31 13:12) [14]


> Клиент посылает серверу пакет, содержащий несколько полей
> (пакет 50 байт)


Покажи как сервер принимает эти 50 байт ..


 
Новичоккк   (2006-05-31 13:21) [15]

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


 
Сергей М. ©   (2006-05-31 13:35) [16]


> Два типа ответа - 18 байт и 50 байт. .. В соответствии
> с чем устанавливается флаг (0 или 1, OK или ERROR).


Твой код противоречит этому !

Если 18 байт - это ОК, а 50 байт - это ERROR, то почему


> if Length(str)=50 then
>  begin
>   done:=true; //а это вообще непонятно - флаг DONE=True прервет цикл while not DONE do..
>   AddInfo("OK: "+aSock[tag].p,clGreen,"["+IntToStr(tag)+"] ",clPurple);
>   aSock[tag].r:=lOK;
>  end;


?!


 
Новичоккк   (2006-05-31 13:39) [17]

Я не это имел ввиду =) "В соответствии" имеет немного другой смысл =)


 
Сергей М. ©   (2006-05-31 13:59) [18]


> "В соответствии" имеет немного другой смысл


Я не телепат и разгадывать твои тайные смыслы у меня нет желания.

Так что изволь сопоставить свой "другой смысл" с примером кода..


 
Новичоккк   (2006-05-31 17:29) [19]

Код в первом примере. В посте [13] в "Два типа ответа - 18 байт и 50 байт. В данном случае содержимое ответов не важно - главное длина ответа. В соответствии с чем устанавливается флаг (0 или 1, OK или ERROR)."
Имелось ввиду не то, что "18 байт"="0" или "ОК" и "50 байт"="1" или "ERROR", а что всего два варианта интерпретации. Порядок соблюден не был.
В соответствии с чем ваш пост [16] не имеет смысла.

Вообще я изначально спросил - в каком месте идёт не правильная работа с сокета, в следствии чего несколько сокетов получают один и тот же ответ (или получают чужие ответы), при этом какие-то ответы могут быть утеряны - т.е. возникают коллизии. Я понятия не имею почему там происходит. Поэтому я и создал ветку - спросить у вас. В данном случае какой ответ воспринимается как OK или ERROR, 18 байт или 50 - значения не имеет.


 
Сергей М. ©   (2006-05-31 17:37) [20]

Если утверждение [2] верно (что весьма сомнительно), то ошибка не в приведенном коде


 
Новичоккк   (2006-05-31 17:52) [21]


> Если утверждение [2] верно (что весьма сомнительно)


Добавил условие:
if not ((Length(str)=11) or (Length(str)=18) or (Length(str)=50)) then ShowMessage("");

Сообщение не было выведено ни разу


> то ошибка не в приведенном коде


В принципе это почти весь код. Что же, попробую написать упрощенную версию сервера и клиента (работающего по такому же принципу с массивом сокетов), будут ли ошибки, или их не будет...


 
Сергей М. ©   (2006-06-01 08:29) [22]


> Сообщение не было выведено ни разу


Разнеси клиент и сервер по разным хостам (даже в пределах ЛВС) и рано или поздно получишь это сообщение.


> с массивом сокетов


Зачем тебе тот массив дался - ума не приложу.
Ты сам себе усложнил задачу с этим массивом.
На то есть TComponent.Owner


 
Новичоккк   (2006-06-01 12:46) [23]


> Зачем тебе тот массив дался - ума не приложу.Ты сам себе
> усложнил задачу с этим массивом.На то есть TComponent.Owner

Можно подробнее?

2All
Может кто-нибудь знает в чем проблема (код в первом посте)



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

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

Наверх




Память: 0.53 MB
Время: 0.042 c
1-1147792675
TStas
2006-05-16 19:17
2006.06.25
Рисование на канве другого приложения


2-1149362980
barzini
2006-06-03 23:29
2006.06.25
Дипломная. БД. Хелп.


6-1139817774
Anton_123
2006-02-13 11:02
2006.06.25
Delphi, Web & RealVideo


4-1143231811
Delphi_is_cool
2006-03-24 23:23
2006.06.25
Как изменить цвет шрифта ? (Static)


15-1149166567
tesseract
2006-06-01 16:56
2006.06.25
Весело AMD хочет купить ATI?