Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2008.10.26;
Скачать: [xml.tar.bz2];

Вниз

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

 
Андрей_Св   (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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.006 c
3-1208347832
Анна
2008-04-16 16:10
2008.10.26
Какие нужно дать права на создание ХП


15-1220428472
clickmaker
2008-09-03 11:54
2008.10.26
Неверный запрос в "Начинающих"


2-1221686355
DBGrid
2008-09-18 01:19
2008.10.26
Убрать ScrollBar


2-1221741033
renex
2008-09-18 16:30
2008.10.26
программно создать компонент


1-1200983736
frostyland
2008-01-22 09:35
2008.10.26
Как программно скроллировать окно, чтобы сделать видимым контрол?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский