Конференция "Сети" » Сервер [D6]
 
  • Андрей_Св (08.11.07 14:53) [0]
    Уважаемые мастера.
    ОТветьте пожалуйста на мой вопрос.
    Пишу сервер IP на WinAPI.
    Вроде бы все нормально, когда
    подключается клиент, определяется его IP,
    заносим в массив на событие FD_ACCEPT wParam-
    то есть в каком сокете произошло событие.
    Массив потом наполняется клиентами с wParam.
    Но когда я хочу передать информацию всем клиентам,
    кажется просто:
      for ix:=Low(MainArrayofClients) to High(MainArrayofClients) do
      begin
         SendText(MainArrayofClients[ix].Socket,IntTostr(Value));
      end;
    Но сокеты уже странно поменялись и передача происходит не туда.
    Как быть?

    const
    WM_ASYNC_CLIENTEVENT = WM_USER + 14;
    MaxClient = High(Word);

    type
      PUser = ^TUser;
      TUser = record
         Name:array[0..255] of Char;
         Socket:Integer;
    end;

    type
      TMainArray = array of TUser;

    var
    MainArrayofClients:TMainArray;
     sServ:TSocket;
     addr,ClientAddr:TSockAddrin;
     WSAEvent:Integer;
     ErrorCode: Integer;

    function SendText(const FSocket:Integer; s:string): Integer;
    var
      FSection: TRTLCriticalSection;
    begin
     FSection.LockSemaphore:=FSocket;
     InitializeCriticalSection(FSection);
     EnterCriticalSection(FSection);
     try
      Result := send(FSocket, Pointer(S)^, Length(S),0);
     finally
      LeaveCriticalSection(FSection);
     end;
    end;

    procedure StartServer;
    var
       par:Integer;
       WSAData:PWSAData;
    begin
      try
         par:=1;
         New(WSAData);
         if WSAStartup(MakeWord(1,1),WSAData^) <>0 then
         begin
            ErrorCode:=WSAGetLastError;
            Dispose(WSAData);
            Exit;
         end;
         if WSAData <> nil then
            Dispose(WSADAta);
         sServ:= socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
         if sServ = INVALID_SOCKET then
         begin
            ErrorCode:=WSAGetLastError;
            CloseSocket(sServ);
            Exit;
         end;
         if WinSock.ioctlsocket(sServ,FIONBIO,par) = SOCKET_ERROR then
         begin
            ErrorCode:=WSAGetLastError;
            CloseSocket(sServ);
            Exit;
         end;
         Addr.sin_family:=AF_INET;
         Addr.sin_port:=htons(20000);
         Addr.sin_addr.S_addr:=htonl(INADDR_ANY);
         if bind(sServ,Addr,Sizeof(Addr)) = SOCKET_ERROR then
         begin
            CloseSocket(sServ);
            ErrorCode:=WSAGetLastError;
            Exit;
         end;
         if WinSock.listen(sServ,MaxClient) = SOCKET_ERROR then
         begin
            CloseSocket(sServ);
            ErrorCode:=WSAGetLastError;
            Exit;
         end;
         AddInfo(Done + #32 + GetDate('.') + #32 + GetTime(':'));
         AddInfo(Listen);
         WinSock.WSAAsyncSelect(sServ,LocalAPP,WM_ASYNC_CLIENTEVENT,FD_ACCEPT or
            FD_READ or FD_WRITE or FD_CONNECT or FD_CLOSE);
      except
         MessageBox(LocalAPP,Error1,ServerName,MB_OK+MB_ICONSTOP);
      end;
    end;

    function GetUser(const ID:Integer):string;
    var
      i:Integer;
    begin
      for i:=Low(MainArrayofClients) to High(MainArrayofClients) do
      begin
        if MainArrayofClients[i].Socket = ID then
         begin
            Result:=MainArrayofClients[i].Name;
            Break;
         end;
      end;
      if Length(Result) = 0 then
         Result:=UnknownPerson;
    end;

    procedure AddClientToServer(const Index:Integer);
    var
      iSize:Integer;
      s:string;
    begin
      iSize:=SizeOf(ClientAddr);
      ErrorCode:=accept(sServ,@clientaddr,@iSize);
      if ErrorCode = INVALID_SOCKET then
      begin
         ErrorCode:=WSAGetLastError;
         CloseSocket(Index);
         Exit;
      end;
      Inc(Count);
      s:=Client + #32 + WinSock.inet_ntoa(clientaddr.sin_addr) + #32 +
         Connect + #32 + GetDate('.') + #32 + GetTime(':');
    end;

    procedure AddIPClient(var A: TMainArray; const AName:string; const Socket:Integer);
    var
      i:Integer;
      Len:Integer;
      Add:Boolean;
      s,bd:string;
    begin
      Add:=True;
      for i:=Low(A) to High(A) do
      if (Socket = A[i].Socket) then
      begin
         Add:=False;
         Break;
      end;
      if Add then
      begin
         Len:=Length(A);
         SetLength(A,Len+1);
         A[Len].Socket:=Socket;
         StrPCopy(A[Len].Name,AName);
         bd:=GetUser(Socket);
         if Length(bd) = 0 then
            bd:=UnknownPerson;
         s:=Identification + ':' + #32 + '"' + bd + '"';
         Exit;
      end;
    end;

    function WndProc(WndA : HWND; message : UINT; wParam : Integer; lParam: Integer) : Integer; stdcall;
    begin
     case message of
       WM_ASYNC_CLIENTEVENT:
         begin
            ErrorCode:=WinSock.WSAGetSelectError(lparam);
            if ErrorCode <> 0 then
            begin
               Result:=0;
               CloseActiveSocket(wParam);
               Exit;
            end;
            WSAEvent:=WinSock.WSAGetSelectEvent(lparam);
            case WSAEvent of
               FD_ACCEPT:
                  begin
                     AddClientToServer(wParam);
                     AddIPClient(MainArrayofClients, GetUser(wParam),wParam);
                  end;
               FD_READ:
                  begin

                  end;
               FD_WRITE:
                  begin
                      SendText(Wparam,Inttostr(Value));
                  end;
               FD_CLOSE:
                  begin
                     CloseSocket(wParam);
                  end;
            end;
            Result:=0;
         end;

    WM_COMMAND:
       begin
         case Loword(wparam) of
    SetupButton:
            begin
               Value:=Random(RandSeed);
               s:=RandomValueText+#32+IntToStr(Value);
               Windows.SetDlgItemText(LocalAPP,id_Random,PChar(s));
               for ix:=Low(MainArrayofClients) to High(MainArrayofClients) do
               begin
                  SendText(MainArrayofClients[ix].Socket,IntTostr(Value)); - ничего не происходит.
               end;
            end;
    end;
  • Сергей М. © (08.11.07 15:08) [1]
    Жуть)

    Для начала ответь, что за блажь - изобретать очередной кривой EinsockAPI-велосипед ? Чем не угодили готовые компонентные реализации серверной логики ?
  • Иван_А (08.11.07 15:22) [2]
    А что за готовые компонентные реализации серверной логики, TServerSocket
    или TClientSocket - полная фигня. В сети из-за них полная труба. А он молодец пишет на WinApi. Такие компоненты сам не люблю.
  • Сергей М. © (08.11.07 15:27) [3]

    > TServerSocket .. полная фигня


    "Вы не любите кошек ? Да вы просто не умеете их готовить !" (с)


    > или TClientSocket


    Речь вообще-то идет о серверной логике.


    > В сети из-за них полная труба


    А это уже личная половая драма вовремя и всерьез не заинтересовавшихся тонкостями сантехники)


    > А он молодец пишет на WinApi


    Кулибиными и славна Держава)


    > Такие компоненты сам не люблю


    Умоляю, только не приводи сюда в кач-ве примера свой фрагмент кода соответствующей серверной логики)
  • Anatoly Podgoretsky © (08.11.07 15:54) [4]
    Скажи у тебя еще есть код?
    Кидай сюда не стесняйся.
  • DVM © (08.11.07 17:08) [5]

    > Для начала ответь, что за блажь - изобретать очередной кривой
    > EinsockAPI-велосипед ? Чем не угодили готовые компонентные
    > реализации серверной логики ?

    готовые как правило бывают не очень удобны для отдельно взятой конкретной задачи.
  • Сергей М. © (09.11.07 12:23) [6]

    > DVM ©   (08.11.07 17:08) [5]


    Бесспорно.
    Но судя по коду никакой выдающейся задачи, той что не могла бы быть решена готовыми средствами,  и не стоит.
  • Prostoy_paren (09.11.07 13:50) [7]
    procedure AddClientToServer(const Index:Integer);
    var
     iSize:Integer;
     s:string;begin
     iSize:=SizeOf(ClientAddr);
     ErrorCode:=accept(sServ,@clientaddr,@iSize);
     if ErrorCode = INVALID_SOCKET then
     begin
        ErrorCode:=WSAGetLastError;
        CloseSocket(Index);
        Exit;
     end;
     Inc(Count);
     s:=Client + #32 + WinSock.inet_ntoa(clientaddr.sin_addr) + #32 +
        Connect + #32 + GetDate('.') + #32 + GetTime(':');

    end;

    Что делает эта процедура?

    И где ты добавляеш клиента в список?
  • Prostoy_paren (09.11.07 13:57) [8]
    function SendText(const FSocket:Integer; s:string): Integer;
    var
     FSection: TRTLCriticalSection;

    begin
    FSection.LockSemaphore:=FSocket;
    InitializeCriticalSection(FSection);
    EnterCriticalSection(FSection);
    try
     Result := send(FSocket, Pointer(S)^, Length(S),0);
    finally
     LeaveCriticalSection(FSection);
    end;
    end;
    Это вообще бред!

    Используеш критические секции в основном потоке, хотя используеш оконные функции и перед посылкой строки просто поставь проверку на ее длину, если она пустая, то и не посылай!
    И try except здесь нафиг не нужны... Ж)
  • Prostoy_paren (09.11.07 14:15) [9]
    И еще к дополнения вопроса к -> [7]:

    ErrorCode:=accept(sServ,@clientaddr,@iSize);

    //Если ацепт вернул ошибку то, что ты Закрываешь?
    if ErrorCode = INVALID_SOCKET then
    begin
       ErrorCode:=WSAGetLastError;
       CloseSocket(Index);
       Exit;
    end;
    И вообще где ты записал ErrorCode!!!?????

    Или ACCEPT здесь для виду запускалась?
  • Prostoy_paren (09.11.07 14:20) [10]
    FD_ACCEPT:
                 begin
                    AddClientToServer(wParam);
                    AddIPClient(MainArrayofClients, GetUser(wParam),wParam);
                 end;
    В wParam прийдет сокет серверного гнезда, а не новый клиентский!!!!
    Вот и спрашивается, а почему у меня сокеты куда-то бегают.
    И при первой же попытке закрыть клиента ты у г@ндониш свой сервер!
    (P.S. Извини модератор по другому сказать не могу :) )
  • Prostoy_paren (09.11.07 14:23) [11]
    И послать сообщение на слушающее гнездо это просто КРУТО!!! Ж)
    ВАМ МНОГОУВАЖАЕМЫЙ СЮДА!!!!!!!!!!
    http://book.itep.ru/7/sock_71.htm
  • Prostoy_paren (09.11.07 14:28) [12]
    А то развели ВЕЛОСИПЕДЫ, ВЕЛОСИПЕДЫ....
    Я, между прочим, когда начинал, тоже такие вопросы задавал и спасибо Digitman-у и Anatoly Podgoretsky ©  за помощь иначе умников в стране много, а помочь толком или указать на ошибки всем влом!!!
    А то блин, тут некоторые сразу с клавиатурой из мамы вышли, а про WinSock еще в утробе лекции прослушали..... >:\
  • DVM © (09.11.07 15:37) [13]

    > Prostoy_paren   (09.11.07 13:57) [8]


    > И try except здесь нафиг не нужны... Ж)

    Там их и нет. А вот try...finally там стоит все же правильно.
  • Сергей М. © (09.11.07 17:05) [14]

    > try...finally там стоит все же правильно


    По-хорошему send() не может вызвать исключение (равно как и прочие WSAPI-вызовы), так что finally там действительно неуместен.
  • DVM © (09.11.07 21:53) [15]

    > Сергей М. ©   (09.11.07 17:05) [14]

    Исключения могут возникнуть везде, даже там где их не ждешь.
    Как то я задавал вопрос в этой конференции и мы его как раз с Вами тут обсуждали. Я не мог понять почему у меня доп поток, в котором происходило соединение и получение данных самопроизвольно умирал. Причем это происходило на одном из компьютеров (как я экспериментально выяснил потом тут был виноваты одновременно работающие 2 файерволла и 1 антивирус, которые в определенных обстоятельствах вызывали AV при обращении к функции Connect()).
    По Вашему совету добавил обработку исключений и выяснилось, что исключение действительно происходило. Параметры функции передавались верные, проверял неоднократно.

    По-моему, лучше окружать try...finally любые места, где происходит выделение/освобождение ресурсов или, например, вход и выход в крит секцию и т.д.
  • Prostoy_paren (10.11.07 00:12) [16]
    >DVM ©
    Скажи, а нужно ли было использовать критические секции если автор использует оконные функции? Какие там намеки на критические секции?
    Тем более, что пишет даже не классы и не использует это в отдельном код потоке.
    Я так понял, что автор взял SCKTCOMP и не правильно от трактовал то, что в нем написано. Я рассказал про недочеты, возможно немного нагрубил :)
    А насчет выделения ресурсов и Try...finally и Try...Except это зависит от реализации самого автора.
    Если процедуру передается строка и даже не по ссылке!
    То какая речь может быть о выделении ресурсов? Эта строка давно уже лежит в стеке!
    И это объявление Send(...,pointer(S)^,Length(S),0);

    Почему не просто Send(...,S[1],Length(S),0);
    и скажем проверку If Length(S)>0 Then ... ;
    И Try ... Finally не нужны!

    Я не сталкивался, чтобы кто-то ставил два файрвола на машину и как они себя будут при этом вести даже не могу предположить :), поэтому я именно так отозвался о выше описанной конструкции.
  • DVM © (10.11.07 01:23) [17]

    > Скажи, а нужно ли было использовать критические секции если
    > автор использует оконные функции? Какие там намеки на критические
    > секции?

    Мне честно говоря лень изучать также внимательно код автора, но я не вижу места куда бы можно было приткнуть с пользой критическую секцию в однопоточном сервере на асинхронных сокетах на сообщениях.


    > Тем более, что пишет даже не классы

    Лучше бы он классом все оформил.


    > Если процедуру передается строка и даже не по ссылке!
    > То какая речь может быть о выделении ресурсов? Эта строка
    > давно уже лежит в стеке!
    > И это объявление Send(...,pointer(S)^,Length(S),0);
    >
    > Почему не просто Send(...,S[1],Length(S),0);
    > и скажем проверку If Length(S)>0 Then ... ;
    > И Try ... Finally не нужны!

    У автора полно недочетов в коде - это бесспорно.

    Насчет try...finally - я ставлю их уже на автомате в тех местах, где они сами просятся.
  • Anatoly Podgoretsky © (10.11.07 12:19) [18]
    > DVM  (10.11.2007 01:23:17)  [17]

    > Насчет try...finally - я ставлю их уже на автомате в тех местах, где они сами просятся.

    Дожил
  • Prostoy_paren (10.11.07 14:05) [19]
    >Anatoly Podgoretsky ©
    >Дожил


    Точно точно... ;)
    без обид
  • Prostoy_paren (10.11.07 19:16) [20]
    Автор наверное написал вопрос и забыл про него!
    Хоть бы раз отозвался, а то парафиним его, а он даже об этом не знает!
    Может какие изменения произошли в коде?
Есть новые Нет новых   [134431   +10][b:0][p:0.001]