Newsgroup: it.comp.lang.delphi
Titolo: [KYLIX] Sockets: send API: broken pipe error if client disconnects

Allora, ho un problema con kylix che mi sta facendo diventare scemo..
L'ho postato sui gruppi della borland, ora lo posto anche qui per sicurezza.
E' in inglese, mi scuso se qualcuno trova qualche difficolta'..
E' veramente un disastro questo problema, spero vivamente che qualcuno di
voi mi sappia aiutare..
--
Ok i tried and search on google but i couldn't find an answare..
I'm using sockets in Kylix3 Enterprise and Knoppix. I created a
multithreaded server to answare client requests.
Now the problem is: if client disconnect and server use the "send" command
after disconnection, i've got a strange "broken pipe" (SIGPIPE) error. This
error is completely immune from try..except block, and causes the program to
close immediatly if run outside the IDE.
n:=send(s,'ciao', 4, 0);
It is strange becouse the "send" command should simply return -1 if it
couldn't send the data, and this is the behaviour of Windows2000's send
command (i'm developing a cross platform server).
I've made a test program to replicate this error. The delphi program is the
server (you press button1 to start the server and button2 to wait for a
connection). Then a small python script connects to the server, send a
message and disconnects immediately. This cause the server to keep sending
message (once a second) after disconnect.
In windows the output is normally -1 sequence, in Linux it just close with
SIGPIPE signal.
if it is a known problem or you have the solution please help me..
PYTHON script
import socket
CRLF = '\r\n'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.2',4000))
s.send('Hello!')
s.send(CRLF)
UNIT1.PAS
unit Unit1;
interface
uses
  SysUtils, Types, Classes, Variants, QTypes, QGraphics, QControls, QForms,
  QDialogs, QStdCtrls, libc;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  serverSocket:TSocket;
implementation
{$R *.xfm}
procedure EsciProcesso(exitvalue:cardinal);
begin
   {$IFDEF MSWINDOWS}
    ExitProcess(exitvalue);
   {$ENDIF}
   {$IFDEF LINUX}
    __exit(exitvalue);
   {$ENDIF}
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  address:sockaddr_in;
  {$IFDEF MSWINDOWS}
    WSAdata:TWSAData;
  {$ENDIF}
begin
  {$IFDEF MSWINDOWS}
    WSAStartup ($0101,WSAdata);     //inizializziamo la DLL delle socket
  {$ENDIF}
  FillChar(address, sizeof(address),0); // settiamo address dicendo che tipo
di socket vogliamo
  address.sin_family := PF_INET;
  address.sin_port := htons(4000);
  serverSocket := socket(AF_INET, SOCK_STREAM, 0); // otteniamo il server
socket
  sleep(1000);
  // lo bindiamo
  if bind(serverSocket,address,sizeof(sockaddr_in))<>0 then
   begin
    EsciProcesso(1);
    exit;
   end;
  // e iniziamo l'ascolto
  if listen(serverSocket, 100)<>0 then
   begin
    EsciProcesso(1);
    exit;
   end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var siz:integer;
    s:Tsocket;
    sockadd:Tsockaddr; // la stuttura contentente le info dell'ultima
connessione
    i,n:integer;
begin
siz:=sizeof(sockadd);
s:=accept(ServerSocket,@sockadd, @siz); // accetta una nuova connessione (la
mette in s)
for i:=0 to 9 do
 begin
  sleep(1000);
  n:=send(s,'ciao', 4, 0);
  memo1.lines.add(inttostr(n));
 end;
end;
end.

Mi hanno risposto sui gruppi borland.
Se a qualcuno interessa, ecco la risposta:
hi, that's linux default  read the man-entry for socket (> man 2 socket)
but
if you specify MSG_NOSIGNAL as flag for send
(n:=send(s,'ciao', 4, [your flags] or MSG_NOSIGNAL ) ) (> man 2 send)
you will only get a error EPIPE and not a signal
you can see that in the indy-source in IdStackLinux.pas
(btw: they missed that also in the beginning ;)) )