Forum > Networking and Web Programming

[SOLVED] SOCKETS fpsend fails, loses 1 character.

(1/2) > >>

arturogr:
Hello,

when SENDING 20 BYTES or more, OF DATA using "fpsend" SOCKETS function in a client applicatilon:

//in the client side, Buffer is 20 bytes long
Result := fpsend(SockDesc, @Buffer, SizeOf(Buffer), 1); // the flag is 1 (I got it from an example)

the server application, "RecvSize" does not report the same number of characters sent by the client when using "fprecv":

//in the server side, Buffer is 30 bytes long
RecvSize := fprecv(clientId, @Buffer, SizeOf(Buffer), 0);  // the flag is 0 (I got it from an example)


if I change an increase the Buffer size in the client side to:
Result := fpsend(SockDesc, @Buffer, SizeOf(Buffer)+1, 1); // the flag is 1 (I got it from an example)

the server side get the total of the message transmited by the client.

In the example code provided, you can view it only when transmiting 20 or more characters. But I think the server does not get the last byte of the message in the transmition.

┬┐Any idea of the problem?

Regards.

===========
SERVER:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program socket_server; {$mode objfpc}{$H+}{  Program to test sockets and get working example of Sockets unit.  This is the single thread server part.  Use the client part to send data to that server.  Inspired from fpConnect / fpAccept examples} uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}  Classes,  Sockets,  SysUtils  { you can add units after this }; var  // Sockets descriptors  SockDesc: longint;  clientId: longint;  // Sockets addresses  SockAddr: TInetSockAddr;  ClientAddr: TInetSockAddr;  // Message  Buffer: array [1..30] of char;   Mensaje: string;  AddrSize: longint;  RecvSize: longint;  StartTimer: longint;   procedure perror(const S: string);  var    ErrorMsg: string;  begin    case socketerror of      EsockADDRINUSE: ErrorMsg := 'Error number when socket address is already in use';      EsockEACCESS: ErrorMsg := 'Access forbidden error';      EsockEBADF: ErrorMsg := 'Alias: bad file descriptor';      EsockEFAULT: ErrorMsg := 'Alias: an error occurred';      EsockEINTR: ErrorMsg := 'Alias : operation interrupted';      EsockEINVAL: ErrorMsg := 'Alias: Invalid value specified';      EsockEMFILE: ErrorMsg := 'Error code ?';      EsockEMSGSIZE: ErrorMsg := 'Wrong message size error';      EsockENOBUFS: ErrorMsg := 'No buffer space available error';      EsockENOTCONN: ErrorMsg := 'Not connected error';      EsockENOTSOCK: ErrorMsg := 'File descriptor is not a socket error';      EsockEPROTONOSUPPORT: ErrorMsg := 'Protocol not supported error';      EsockEWOULDBLOCK: ErrorMsg := 'Operation would block error';      else        ErrorMsg := 'Undescribed error : ' + IntToStr(socketerror);    end;    writeln(S, ErrorMsg);    halt(100);  end; begin  SockDesc := fpSocket(AF_INET, SOCK_STREAM, 0);  if SockDesc = -1 then    Perror('[Server] Socket : ');  SockAddr.sin_family := AF_INET;  // Port 8008  SockAddr.sin_port := htons(8008);  // Look on all interfaces so address 0.0.0.0  SockAddr.sin_addr := StrToNetAddr('0.0.0.0');  // Bind socket  if fpBind(SockDesc, @SockAddr, sizeof(SockAddr)) = -1 then    PError('[Server] Bind : ');  // Turn socket into listening state  if fpListen(SockDesc, 1) = -1 then    PError('[Server] Listen : ');  // Waiting client connection  Writeln('Waiting for client connection, run now client in an other tty');  // Accept client connection  AddrSize := sizeof(ClientAddr);   while True do  begin    clientId := fpAccept(SockDesc, @ClientAddr, @AddrSize);    if clientId = -1 then      PError('[Server] Accept : ' + NetAddrToStr(ClientAddr.sin_addr))    else      writeln('[Server] New client connected from: ' + NetAddrToStr(ClientAddr.sin_addr));    // Read data    RecvSize := fprecv(clientId, @Buffer, SizeOf(Buffer), 0);    Mensaje := Buffer;    while RecvSize > 0 do    begin      if RecvSize > 0 then        writeln('[Server] Receive : ' + Mensaje + ' [' + IntToStr(RecvSize) + ']');      RecvSize := fprecv(clientId, @Buffer, SizeOf(Buffer), 0);      Mensaje := Buffer;    end;    if (RecvSize = 0) and (SocketError = 0) then    begin      writeln('[Server] Client disconnect.');      writeln('');    end;    if RecvSize = -1 then      PError('[Server] Read failed : ');  end;end.              
============
CLIENT:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program socket_client; {  Program to test sockets and get working example of Sockets unit.  This is the client part. The server part must be start before using this one.  Inspired from fpConnect / fpAccept examples} {$mode objfpc}{$H+} uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}  Classes,  Sockets,  SysUtils  { you can add units after this };   procedure PError(const S: string);  var    ErrorMsg: string;  begin    case socketerror of      EsockADDRINUSE: ErrorMsg := 'Error number when socket address is already in use';      EsockEACCESS: ErrorMsg := 'Access forbidden error';      EsockEBADF: ErrorMsg := 'Alias: bad file descriptor';      EsockEFAULT: ErrorMsg := 'Alias: an error occurred';      EsockEINTR: ErrorMsg := 'Alias : operation interrupted';      EsockEINVAL: ErrorMsg := 'Alias: Invalid value specified';      EsockEMFILE: ErrorMsg := 'Error code ?';      EsockEMSGSIZE: ErrorMsg := 'Wrong message size error';      EsockENOBUFS: ErrorMsg := 'No buffer space available error';      EsockENOTCONN: ErrorMsg := 'Not connected error';      EsockENOTSOCK: ErrorMsg := 'File descriptor is not a socket error';      EsockEPROTONOSUPPORT: ErrorMsg := 'Protocol not supported error';      EsockEWOULDBLOCK: ErrorMsg := 'Operation would block error';      else        ErrorMsg := 'Undescribed error : ' + IntToStr(socketerror);    end;    writeln(S, ErrorMsg);  end; var  // Socket descriptor  SockDesc: longint;  // Socket address  SockAddr: TInetSockAddr;  // Message  Buffer: array [1..20] of char;  //string[255];  i, j: longint;  Result: longint;   Mensaje: string;begin  SockDesc := fpSocket(AF_INET, SOCK_STREAM, 0);  if SockDesc = -1 then    Perror('[Client] Socket : ');  SockAddr.sin_family := AF_INET;  // Port 8008  SockAddr.sin_port := htons(8008);  // Address 127.0.0.1  SockAddr.sin_addr := StrToNetAddr('127.0.0.1');  // Connection  if fpconnect(SockDesc, @SockAddr, SizeOf(SockAddr)) = -1 then    PError('[Client] Connect : ');  // Send data  i:=1;  writeln('send a "-", and the client will disconnect (exit).');  Mensaje := '(' + IntToStr(i) + ') >1st Msg.';  while copy(Mensaje,length(Mensaje),1) <> '-' do  begin    Buffer := Mensaje;    Result := fpsend(SockDesc, @Buffer, SizeOf(Buffer), 1);    writeln(Buffer + ' [TX=' + IntToStr(Result) + ' / Data=' + IntToStr(SizeOf(Buffer)) + ']');    if Result <> (SizeOf(Buffer)) then      PError('[ERROR Client] Send : ');    sleep(5);    i := i+1;    readln(Mensaje);    Mensaje := '(' + IntToStr(i) + ') >' + Mensaje;   end;  writeln('>>> press ENTER to disconnet and EXIT.');  readln();  writeln('>bye!');  // Shutdown communication  if fpshutdown(SockDesc, 2) = -1 then    PError('[Client] Shutdown : ');  // Close socket  if CloseSocket(SockDesc) = -1 then    PError('[Client] Close : ');  sleep(2000);end.                        

MarkMLl:
Full marks for trying, but please chop all of that example code from your message and give us a proper example as an attachment.

Basically, if you just plonk code in like that it's unusable for the rest of us because it's mangled by the forum software.

A first glance doesn't show any of the "usual suspects", i.e. things like trying to take the address of (the data structure describing) a string or a dynamic array rather than taking the address of the first byte. Ditto the current size... you'd be amazed by how many people are caught by that one.

You shouldn't really be trusting random examples. The *documentation* for the sockets unit is at https://www.freepascal.org/docs-html/current/rtl/sockets/index.html and from that you'll see that the final parameter of fpSend() should be zero. I don't recall using anything else, and I work at this level a lot.

MarkMLl

bytebites:
https://www.freepascal.org/docs-html/current/rtl/sockets/fpsend.html

says flag can be 1 or 4, but if you change it to zero, the server gets 20 chars.

Remy Lebeau:

--- Quote from: MarkMLl on November 10, 2023, 07:38:21 am ---Full marks for trying, but please chop all of that example code from your message and give us a proper example as an attachment.

Basically, if you just plonk code in like that it's unusable for the rest of us because it's mangled by the forum software.

--- End quote ---

Or, just use proper code formatting using [ code ][ /code ] tags instead.

Warfley:
Why are you using flags if you don't seem to know what they are doing? Usually in most cases you don't need or want to set any flags and should just pass 0. For further info on what flags exist and what they do check out the man pages:
https://www.man7.org/linux/man-pages/man2/send.2.html
https://www.man7.org/linux/man-pages/man2/recv.2.html

Flag 1 is, at least according to the fpc doc the MSG_OOB flag. also never use numeral constants because this makes finding out what they do difficult. Always use the named constants like MSG_OOB.

About OOB, this flag is specifically for very short messages that need to be handled specially (out of band), see this: https://stackoverflow.com/questions/589928/socket-programming-how-do-i-handle-out-of-band-data

It's only for things like exceptions or similar, and is very limited. Do not use it just for arbitrary data

Navigation

[0] Message Index

[#] Next page

Go to full version