Системное программирование в UNIX средствами Free Pascal


         

Закрытие TCP-соединения


При работе с сокетами важно корректно реагировать на завершение работы абонентского процесса. Так как сокет является двусторонним механизмом связи, то нельзя предсказать заранее, когда произойдет разрыв соединения – во время чтения или записи. Поэтому нужно учитывать оба возможных варианта.

Если процесс пытается записать данные в оборванный сокет при помощи вызова fdwrite или send, то он получит сигнал SIGPIPE, который может быть перехвачен соответствующим обработчиком сигнала. При чтении обрыв диагностируется проще.

В случае разорванной связи вызов fdread или recv возвращает нулевое значение. Поэтому для вызовов fdread и recv необходимо всегда проверять возвращаемое значение, чтобы не зациклиться при приеме данных.

Закрываются сокеты так же, как и обычные дескрипторы файлового ввода/вывода, – при помощи системного вызова fdclose. Для сокета типа

SOCK_STREAM ядро гарантирует, что все записанные в сокет данные будут переданы принимающему процессу. Это может вызвать блокирование операции закрытия сокета до тех пор, пока данные не будут доставлены. (Если сокет имеет тип SOCK_DGRAM, то сокет закрывается немедленно.)

Теперь можно привести полный текст примера клиента и сервера, добавив в серверный процесс обработку сигналов и вызов fdclose в обе программы. В данном случае эти меры могут показаться излишними, но в реальном клиент/серверном приложении обязательна надежная обработка всех исключительных ситуаций. Приведем окончательный текст программы сервера:

(* Серверный процесс *)

uses sockets,stdio,linux;

const

  SIZE=sizeof(tinetsockaddr);

  server:tinetsockaddr = (family:AF_INET; port:7000; addr:INADDR_ANY);

 

var

  newsockfd:longint;

procedure catcher (sig:integer);cdecl;

begin

  fdclose (newsockfd);

  halt (0);

end;

var

  sockfd:longint;

  c:char;

  act:sigactionrec;

  mask:sigset_t;

  client:tinetsockaddr;

  clientaddrlen:longint;

begin

  act.handler.sh := @catcher;

  sigfillset (@mask);

  act.sa_mask:=mask.__val[0];



Содержание  Назад  Вперед