![]() |
|
#1
|
||||
|
||||
![]() Че-то я туплю... Как на WinAPI по-нормальному проверить со стороны сервера, подключен ли клиент?
Пока ничего не придумал лучше, чем Код:
isize:=send(s,buf,buflen,0); Или хоть как получить для send код ошибки? jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 08.12.2010 в 17:41. |
#2
|
||||
|
||||
![]() Цитата:
Код:
procedure check(ASocket: TSocket; ATimeOutWrite: Integer); var ErrorCode: Integer; FDSet: TFDSet; TimeVal: TTimeVal; begin if ASocket=INVALID_SOCKET then raise Exception.Create('invalid socket'); FD_ZERO(FDSet); FD_SET(ASocket, FDSet); TimeVal.tv_sec:=ATimeOutWrite div 1000; TimeVal.tv_usec:=(ATimeOutWrite mod 1000)*1000; select(0, nil, @FDSet, nil, @TimeVal); if not FD_ISSET(ASocket, FDSet) then raise Exception.Create('exception'); end; Пишу программы за еду. __________________ |
#3
|
||||
|
||||
![]() Спасибо вам!
jmp $ ; Happy End! The Cake Is A Lie. |
#4
|
||||
|
||||
![]() Я немного изменил функцию, чтобы она возвращала мне True или False.
Код:
function CheckSock(ASocket: TSocket; ATimeOutWrite: integer): boolean; var ErrorCode: integer; FDSet: TFDSet; TimeVal: TTimeVal; begin result := false; if ASocket = INVALID_SOCKET then raise Exception.Create('invalid socket'); FD_ZERO(FDSet); FD_SET(ASocket, FDSet); TimeVal.tv_sec := ATimeOutWrite div 1000; TimeVal.tv_usec := (ATimeOutWrite mod 1000) * 1000; select(0, nil, @FDSet, nil, @TimeVal); if FD_ISSET(ASocket, FDSet) then result := true; end; В чем ошибка? jmp $ ; Happy End! The Cake Is A Lie. |
#5
|
||||
|
||||
![]() Поднимаю тему снова...
jmp $ ; Happy End! The Cake Is A Lie. |
#6
|
||||
|
||||
![]() Ап Ап Ап Ап Ап
jmp $ ; Happy End! The Cake Is A Lie. |
#7
|
||||
|
||||
![]() Ну хоть кто-нибудь!
jmp $ ; Happy End! The Cake Is A Lie. |
#8
|
||||
|
||||
![]() ну это как бы пример был.
вот: Код:
function CheckSocket(const ASocket: TSocket; usec: Integer): Boolean; var FDSet: TFDSet; TimeVal: TTimeVal; begin if ASocket<>INVALID_SOCKET then begin FD_ZERO(FDSet); FD_SET(ASocket, FDSet); TimeVal.tv_sec:=0; TimeVal.tv_usec:=usec; if select(0, @FDSet, nil, nil, @TimeVal)<>SOCKET_ERROR then Result:=True else Result:=False; end else Result:=False; end; if CheckSocket(sockethandle, 10000микросек) then ...ok... else ...err... Пишу программы за еду. __________________ Последний раз редактировалось NumLock, 17.12.2010 в 14:08. |
#9
|
||||
|
||||
![]() Странно... При отключенном клиенте возвращает не SOCKET_ERROR (-1) а 1...
Поставил Код:
k:=select(0, @FDSet, nil, nil, @TimeVal); if k=0 then ТРУ jmp $ ; Happy End! The Cake Is A Lie. |
#10
|
||||
|
||||
![]() Цитата:
Пишу программы за еду. __________________ |
#11
|
||||
|
||||
![]() Да нет, передаю нормальный...
jmp $ ; Happy End! The Cake Is A Lie. |
#12
|
||||
|
||||
![]() Все никак не разберусь. Вот подробный отчёт:
Код:
k := select(0, @FDSet, nil, nil, @TimeVal); if k = 0 then result := true; Так возвращается 0 если нет данных для чтения (нормально), 1 если есть (тоже нормально), но почему-то 1 (а не -1) если сокет закрыть со стороны клиента. Код:
k := select(0, nil, @FDSet, nil, @TimeVal); if k = 0 then result := true; Текущий способ (первый) не работает, потому что если в течение N-ного времени передаются данные, то соединение слетает (у меня стоит 5 таких проверок по таймеру). Второй - и говорить нечего. Прошу помочь. Уже не представляю что еще может быть не так. jmp $ ; Happy End! The Cake Is A Lie. |
#13
|
||||
|
||||
![]() ну вот полный пример http://data.cod.ru/82129
-в ASocket храним клиента. изначально он INVALID_SOCKET, т.к. никогда не подключался Код:
procedure TForm1.FormCreate(Sender: TObject); begin ASocket:=INVALID_SOCKET; end; -таймер периодически вызывает CheckSocket и выводит результат в Caption. естественно для никогда не подключавшегося клиента ASocket=INVALID_SOCKET procedure TForm1.Timer1Timer(Sender: TObject); Код:
begin if CheckSocket(ASocket, 1000) then Caption:='CheckSocket: True' else Caption:='CheckSocket: False'; Caption:=Caption+' (SocketHandle='+IntToStr(ASocket)+')'; end; -при нажатии кнопки 1 клиент подключается Код:
procedure TForm1.Button1Click(Sender: TObject); begin ClientSocket1.Open; end; Код:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('ClientConnect'); ASocket:=ServerSocket1.Socket.Connections[0].SocketHandle; end; -когда нажимаем кнопку 3 клиент закрывает соединение Код:
procedure TForm1.Button3Click(Sender: TObject); begin ClientSocket1.Close; end; Код:
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('ClientDisconnect'); end; -теперь таймер будет говорить False полный код: Код:
unit Unit1; interface uses WinSock, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ScktComp; type TForm1 = class(TForm) ClientSocket1: TClientSocket; ServerSocket1: TServerSocket; Timer1: TTimer; Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; ClientSocket2: TClientSocket; procedure Button1Click(Sender: TObject); procedure ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); procedure ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); procedure ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } ASocket: TSocket; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} function CheckSocket(const ASocket: TSocket; usec: Integer): Boolean; var FDSet: TFDSet; TimeVal: TTimeVal; begin if ASocket<>INVALID_SOCKET then begin FD_ZERO(FDSet); FD_SET(ASocket, FDSet); TimeVal.tv_sec:=0; TimeVal.tv_usec:=usec; if select(0, @FDSet, nil, nil, @TimeVal)<>SOCKET_ERROR then Result:=True else Result:=False; end else Result:=False; end; procedure TForm1.Button1Click(Sender: TObject); begin ClientSocket1.Open; end; procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('ClientConnect'); ASocket:=ServerSocket1.Socket.Connections[0].SocketHandle; end; procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('ClientDisconnect'); end; procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('ClientRead='+Socket.ReceiveText); end; procedure TForm1.FormCreate(Sender: TObject); begin ASocket:=INVALID_SOCKET; end; procedure TForm1.Timer1Timer(Sender: TObject); begin if CheckSocket(ASocket, 1000) then Caption:='CheckSocket: True' else Caption:='CheckSocket: False'; Caption:=Caption+' (SocketHandle='+IntToStr(ASocket)+')'; end; procedure TForm1.Button2Click(Sender: TObject); begin ClientSocket1.Socket.SendText('hello'); end; procedure TForm1.Button3Click(Sender: TObject); begin ClientSocket1.Close; end; end. естественно проверка состояния сокета для не блокируемых сокетов (событийных) это только для примера. там и так ясно когда клиент туту. Пишу программы за еду. __________________ Последний раз редактировалось NumLock, 28.12.2010 в 10:56. |
#14
|
||||
|
||||
![]() Код:
procedure TServerClientThread.ClientExecute; var FDSet: TFDSet; TimeVal: TTimeVal; begin while not Terminated and ClientSocket.Connected do begin FD_ZERO(FDSet); FD_SET(ClientSocket.SocketHandle, FDSet); TimeVal.tv_sec := 0; TimeVal.tv_usec := 500; if (select(0, @FDSet, nil, nil, @TimeVal) > 0) and not Terminated then if ClientSocket.ReceiveBuf(FDSet, -1) = 0 then Break else Synchronize(DoRead); if (select(0, nil, @FDSet, nil, @TimeVal) > 0) and not Terminated then Synchronize(DoWrite); end; end; Код:
function TCustomWinSocket.ReceiveBuf(var Buf; Count: Integer): Integer; var ErrorCode, iCount: Integer; begin Lock; try Result := 0; if (Count = -1) and FConnected then ioctlsocket(FSocket, FIONREAD, Longint(Result)) else begin if not FConnected then Exit; if ioctlsocket(FSocket, FIONREAD, iCount) = 0 then begin if (iCount > 0) and (iCount < Count) then Count := iCount; end; Result := recv(FSocket, Buf, Count, 0); if Result = SOCKET_ERROR then begin ErrorCode := WSAGetLastError; if ErrorCode <> WSAEWOULDBLOCK then begin Error(Self, eeReceive, ErrorCode); Disconnect(FSocket); if ErrorCode <> 0 then raise ESocketError.CreateResFmt(@sWindowsSocketError, [SysErrorMessage(ErrorCode), ErrorCode, 'recv']); end; end; end; finally Unlock; end; end; Тогда не удивительно, что функция для ASocket начинает возвращать ошибку - ведь ASocket это число, ссылка. Сам сокет уже закрыт сервером т.к. была ошибка чтения. Почитал код ServerSocket - решил встроить такую же проверку в свой код. Встроил. Вроде работает нормально. Спасибо NumLock, что направили на этот компонент. По умолчанию его в Delphi XE нету... jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 28.12.2010 в 14:47. |