-
Уважаемые мастера. ОТветьте пожалуйста на мой вопрос. Пишу сервер 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;
-
Жуть)
Для начала ответь, что за блажь - изобретать очередной кривой EinsockAPI-велосипед ? Чем не угодили готовые компонентные реализации серверной логики ?
-
А что за готовые компонентные реализации серверной логики, TServerSocket или TClientSocket - полная фигня. В сети из-за них полная труба. А он молодец пишет на WinApi. Такие компоненты сам не люблю.
-
> TServerSocket .. полная фигня
"Вы не любите кошек ? Да вы просто не умеете их готовить !" (с)
> или TClientSocket
Речь вообще-то идет о серверной логике.
> В сети из-за них полная труба
А это уже личная половая драма вовремя и всерьез не заинтересовавшихся тонкостями сантехники)
> А он молодец пишет на WinApi
Кулибиными и славна Держава)
> Такие компоненты сам не люблю
Умоляю, только не приводи сюда в кач-ве примера свой фрагмент кода соответствующей серверной логики)
-
Скажи у тебя еще есть код? Кидай сюда не стесняйся.
-
> Для начала ответь, что за блажь - изобретать очередной кривой > EinsockAPI-велосипед ? Чем не угодили готовые компонентные > реализации серверной логики ?
готовые как правило бывают не очень удобны для отдельно взятой конкретной задачи.
-
> DVM © (08.11.07 17:08) [5]
Бесспорно. Но судя по коду никакой выдающейся задачи, той что не могла бы быть решена готовыми средствами, и не стоит.
-
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;
Что делает эта процедура?
И где ты добавляеш клиента в список?
-
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 здесь нафиг не нужны... Ж)
-
И еще к дополнения вопроса к -> [7]:
ErrorCode:=accept(sServ,@clientaddr,@iSize);
//Если ацепт вернул ошибку то, что ты Закрываешь? if ErrorCode = INVALID_SOCKET then begin ErrorCode:=WSAGetLastError; CloseSocket(Index); Exit; end; И вообще где ты записал ErrorCode!!!?????
Или ACCEPT здесь для виду запускалась?
-
FD_ACCEPT: begin AddClientToServer(wParam); AddIPClient(MainArrayofClients, GetUser(wParam),wParam); end; В wParam прийдет сокет серверного гнезда, а не новый клиентский!!!! Вот и спрашивается, а почему у меня сокеты куда-то бегают. И при первой же попытке закрыть клиента ты у г@ндониш свой сервер! (P.S. Извини модератор по другому сказать не могу :) )
-
-
А то развели ВЕЛОСИПЕДЫ, ВЕЛОСИПЕДЫ.... Я, между прочим, когда начинал, тоже такие вопросы задавал и спасибо Digitman-у и Anatoly Podgoretsky © за помощь иначе умников в стране много, а помочь толком или указать на ошибки всем влом!!! А то блин, тут некоторые сразу с клавиатурой из мамы вышли, а про WinSock еще в утробе лекции прослушали..... >:\
-
> Prostoy_paren (09.11.07 13:57) [8]
> И try except здесь нафиг не нужны... Ж)
Там их и нет. А вот try...finally там стоит все же правильно.
-
> try...finally там стоит все же правильно
По-хорошему send() не может вызвать исключение (равно как и прочие WSAPI-вызовы), так что finally там действительно неуместен.
-
> Сергей М. © (09.11.07 17:05) [14]
Исключения могут возникнуть везде, даже там где их не ждешь. Как то я задавал вопрос в этой конференции и мы его как раз с Вами тут обсуждали. Я не мог понять почему у меня доп поток, в котором происходило соединение и получение данных самопроизвольно умирал. Причем это происходило на одном из компьютеров (как я экспериментально выяснил потом тут был виноваты одновременно работающие 2 файерволла и 1 антивирус, которые в определенных обстоятельствах вызывали AV при обращении к функции Connect()). По Вашему совету добавил обработку исключений и выяснилось, что исключение действительно происходило. Параметры функции передавались верные, проверял неоднократно.
По-моему, лучше окружать try...finally любые места, где происходит выделение/освобождение ресурсов или, например, вход и выход в крит секцию и т.д.
-
>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 не нужны!
Я не сталкивался, чтобы кто-то ставил два файрвола на машину и как они себя будут при этом вести даже не могу предположить :), поэтому я именно так отозвался о выше описанной конструкции.
-
> Скажи, а нужно ли было использовать критические секции если > автор использует оконные функции? Какие там намеки на критические > секции?
Мне честно говоря лень изучать также внимательно код автора, но я не вижу места куда бы можно было приткнуть с пользой критическую секцию в однопоточном сервере на асинхронных сокетах на сообщениях.
> Тем более, что пишет даже не классы
Лучше бы он классом все оформил.
> Если процедуру передается строка и даже не по ссылке! > То какая речь может быть о выделении ресурсов? Эта строка > давно уже лежит в стеке! > И это объявление Send(...,pointer(S)^,Length(S),0); > > Почему не просто Send(...,S[1],Length(S),0); > и скажем проверку If Length(S)>0 Then ... ; > И Try ... Finally не нужны!
У автора полно недочетов в коде - это бесспорно.
Насчет try...finally - я ставлю их уже на автомате в тех местах, где они сами просятся.
-
> DVM (10.11.2007 01:23:17) [17]
> Насчет try...finally - я ставлю их уже на автомате в тех местах, где они сами просятся.
Дожил
-
>Anatoly Podgoretsky © >Дожил
Точно точно... ;) без обид
-
Автор наверное написал вопрос и забыл про него! Хоть бы раз отозвался, а то парафиним его, а он даже об этом не знает! Может какие изменения произошли в коде?
|