![]() |
|
|
#1
|
||||
|
||||
|
Че-то я туплю... Как на WinAPI по-нормальному проверить со стороны сервера, подключен ли клиент?
Пока ничего не придумал лучше, чем Код:
isize:=send(s,buf,buflen,0); Или хоть как получить для send код ошибки? Последний раз редактировалось 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
|
||||
|
||||
|
Спасибо вам!
|
|
#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;В чем ошибка? |
|
#5
|
||||
|
||||
|
Поднимаю тему снова...
|
|
#6
|
||||
|
||||
|
Ап Ап Ап Ап Ап
|
|
#7
|
||||
|
||||
|
Ну хоть кто-нибудь!
|
|
#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 ТРУ |
|
#10
|
||||
|
||||
|
Цитата:
|
|
#11
|
||||
|
||||
|
Да нет, передаю нормальный...
|
|
#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 таких проверок по таймеру). Второй - и говорить нечего. Прошу помочь. Уже не представляю что еще может быть не так. |
|
#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 нету... Последний раз редактировалось Bargest, 28.12.2010 в 14:47. |