Форум: "Сети";
Текущий архив: 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