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

Вниз

Сервер   Найти похожие ветки 

 
Андрей_Св   (2007-11-08 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;


 
Сергей М. ©   (2007-11-08 15:08) [1]

Жуть)

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


 
Иван_А   (2007-11-08 15:22) [2]

А что за готовые компонентные реализации серверной логики, TServerSocket
или TClientSocket - полная фигня. В сети из-за них полная труба. А он молодец пишет на WinApi. Такие компоненты сам не люблю.


 
Сергей М. ©   (2007-11-08 15:27) [3]


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


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


> или TClientSocket


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


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


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


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


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


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


Умоляю, только не приводи сюда в кач-ве примера свой фрагмент кода соответствующей серверной логики)


 
Anatoly Podgoretsky ©   (2007-11-08 15:54) [4]

Скажи у тебя еще есть код?
Кидай сюда не стесняйся.


 
DVM ©   (2007-11-08 17:08) [5]


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

готовые как правило бывают не очень удобны для отдельно взятой конкретной задачи.


 
Сергей М. ©   (2007-11-09 12:23) [6]


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


Бесспорно.
Но судя по коду никакой выдающейся задачи, той что не могла бы быть решена готовыми средствами,  и не стоит.


 
Prostoy_paren   (2007-11-09 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   (2007-11-09 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   (2007-11-09 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   (2007-11-09 14:20) [10]

FD_ACCEPT:
             begin
                AddClientToServer(wParam);
                AddIPClient(MainArrayofClients, GetUser(wParam),wParam);
             end;
В wParam прийдет сокет серверного гнезда, а не новый клиентский!!!!
Вот и спрашивается, а почему у меня сокеты куда-то бегают.
И при первой же попытке закрыть клиента ты у г@ндониш свой сервер!
(P.S. Извини модератор по другому сказать не могу :) )


 
Prostoy_paren   (2007-11-09 14:23) [11]

И послать сообщение на слушающее гнездо это просто КРУТО!!! Ж)
ВАМ МНОГОУВАЖАЕМЫЙ СЮДА!!!!!!!!!!
http://book.itep.ru/7/sock_71.htm


 
Prostoy_paren   (2007-11-09 14:28) [12]

А то развели ВЕЛОСИПЕДЫ, ВЕЛОСИПЕДЫ....
Я, между прочим, когда начинал, тоже такие вопросы задавал и спасибо Digitman-у и Anatoly Podgoretsky ©  за помощь иначе умников в стране много, а помочь толком или указать на ошибки всем влом!!!
А то блин, тут некоторые сразу с клавиатурой из мамы вышли, а про WinSock еще в утробе лекции прослушали..... >:\


 
DVM ©   (2007-11-09 15:37) [13]


> Prostoy_paren   (09.11.07 13:57) [8]


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

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


 
Сергей М. ©   (2007-11-09 17:05) [14]


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


По-хорошему send() не может вызвать исключение (равно как и прочие WSAPI-вызовы), так что finally там действительно неуместен.


 
DVM ©   (2007-11-09 21:53) [15]


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

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

По-моему, лучше окружать try...finally любые места, где происходит выделение/освобождение ресурсов или, например, вход и выход в крит секцию и т.д.


 
Prostoy_paren   (2007-11-10 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 ©   (2007-11-10 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 ©   (2007-11-10 12:19) [18]

> DVM  (10.11.2007 01:23:17)  [17]

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

Дожил


 
Prostoy_paren   (2007-11-10 14:05) [19]

>Anatoly Podgoretsky ©
>Дожил


Точно точно... ;)
без обид


 
Prostoy_paren   (2007-11-10 19:16) [20]

Автор наверное написал вопрос и забыл про него!
Хоть бы раз отозвался, а то парафиним его, а он даже об этом не знает!
Может какие изменения произошли в коде?



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

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

Наверх




Память: 0.54 MB
Время: 0.091 c
2-1221721382
Mahno
2008-09-18 11:03
2008.10.26
Помогите с вычислением


15-1220290532
Простой
2008-09-01 21:35
2008.10.26
ИК датчик движения, контакт GND


15-1220467529
Кое кто
2008-09-03 22:45
2008.10.26
Фуникулёр с гидравлическим противовесом


2-1221658980
smartleds
2008-09-17 17:43
2008.10.26
Господа, напомните пожалуйста функцию задержки в Делфи


2-1221715346
Matveih1
2008-09-18 09:22
2008.10.26
Как предотвратить повторный запуск формы?