Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 08.12.2010, 17:37
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию WinSock API

Че-то я туплю... Как на WinAPI по-нормальному проверить со стороны сервера, подключен ли клиент?
Пока ничего не придумал лучше, чем
Код:
isize:=send(s,buf,buflen,0);
и если isize=-1 значит ошибка... однако ошибка будет и в случае, если например переполнен буфер клиента.
Или хоть как получить для send код ошибки?
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 08.12.2010 в 17:41.
Ответить с цитированием
  #2  
Старый 09.12.2010, 10:34
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
The Windows Sockets select function determines the status of one or more sockets, waiting if necessary.
int select (
int nfds,
fd_set FAR * readfds,
fd_set FAR * writefds,
fd_set FAR * exceptfds,
const struct timeval FAR * timeout
);

Parameters

nfds
[in] This argument is ignored and included only for the sake of compatibility.

readfds
[in/out] An optional pointer to a set of sockets to be checked for readability.

writefds
[in/out] An optional pointer to a set of sockets to be checked for writability

exceptfds
[in/out] An optional pointer to a set of sockets to be checked for errors.

timeout
[in] The maximum time for select to wait, or NULL for blocking operation.
что-то типа этого:
Код:
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  
Старый 09.12.2010, 15:44
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Спасибо вам!
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #4  
Старый 11.12.2010, 18:09
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Я немного изменил функцию, чтобы она возвращала мне 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;
Однако почему-то мне всегда возвращается TRUE, даже при отключенном клиенте.
В чем ошибка?
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #5  
Старый 12.12.2010, 20:19
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Поднимаю тему снова...
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #6  
Старый 13.12.2010, 17:54
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Ап Ап Ап Ап Ап
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #7  
Старый 15.12.2010, 22:03
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Ну хоть кто-нибудь!
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #8  
Старый 17.12.2010, 14:06
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

ну это как бы пример был.
вот:
Код:
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  
Старый 17.12.2010, 20:32
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Странно... При отключенном клиенте возвращает не SOCKET_ERROR (-1) а 1...
Поставил
Код:
k:=select(0, @FDSet, nil, nil, @TimeVal);
if k=0 then ТРУ
Пока вроде работает.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #10  
Старый 20.12.2010, 10:00
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
The select function determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.
Return Value
The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, WSAGetLastError can be used to retrieve a specific error code.
handle не перепутал, который передаешь? может серверный передаешь?
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #11  
Старый 20.12.2010, 12:50
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Да нет, передаю нормальный...
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #12  
Старый 28.12.2010, 00:12
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Все никак не разберусь. Вот подробный отчёт:
Код:
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;
так вообще всегда возвращается 1, даже если сокет закрыт.

Текущий способ (первый) не работает, потому что если в течение N-ного времени передаются данные, то соединение слетает (у меня стоит 5 таких проверок по таймеру). Второй - и говорить нечего.

Прошу помочь. Уже не представляю что еще может быть не так.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #13  
Старый 28.12.2010, 10:50
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

ну вот полный пример 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;
и на сервере происходит событие. запоминаем в ASocket клиента
Код:
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;
но в нем не будем трогать ASocket!!! пусть таймер так для этого клиента и проверяет состояние.
-теперь таймер будет говорить 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  
Старый 28.12.2010, 14:39
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Код:
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;
В компоненте ServerSocket вечно проверяется, есть ли буфер для чтения или записи, если есть для чтения - вызывают функцию его чтения.
Код:
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.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 21:08.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025