Recent

Author Topic: [SOLVED] SOCKETS fpsend fails, loses 1 character.  (Read 4159 times)

arturogr

  • Newbie
  • Posts: 5
[SOLVED] SOCKETS fpsend fails, loses 1 character.
« on: November 10, 2023, 05:27:21 am »
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  [Select][+][-]
  1. program socket_server;
  2.  {$mode objfpc}{$H+}
  3. {
  4.   Program to test sockets and get working example of Sockets unit.
  5.   This is the single thread server part.
  6.   Use the client part to send data to that server.
  7.   Inspired from fpConnect / fpAccept examples
  8. }
  9.  
  10. uses
  11.   {$IFDEF UNIX}
  12.   cthreads,
  13.   {$ENDIF}
  14.   Classes,
  15.   Sockets,
  16.   SysUtils
  17.   { you can add units after this };
  18.  
  19. var
  20.   // Sockets descriptors
  21.   SockDesc: longint;
  22.   clientId: longint;
  23.   // Sockets addresses
  24.   SockAddr: TInetSockAddr;
  25.   ClientAddr: TInetSockAddr;
  26.   // Message
  27.   Buffer: array [1..30] of char;
  28.  
  29.   Mensaje: string;
  30.   AddrSize: longint;
  31.   RecvSize: longint;
  32.   StartTimer: longint;
  33.  
  34.   procedure perror(const S: string);
  35.   var
  36.     ErrorMsg: string;
  37.   begin
  38.     case socketerror of
  39.       EsockADDRINUSE: ErrorMsg := 'Error number when socket address is already in use';
  40.       EsockEACCESS: ErrorMsg := 'Access forbidden error';
  41.       EsockEBADF: ErrorMsg := 'Alias: bad file descriptor';
  42.       EsockEFAULT: ErrorMsg := 'Alias: an error occurred';
  43.       EsockEINTR: ErrorMsg := 'Alias : operation interrupted';
  44.       EsockEINVAL: ErrorMsg := 'Alias: Invalid value specified';
  45.       EsockEMFILE: ErrorMsg := 'Error code ?';
  46.       EsockEMSGSIZE: ErrorMsg := 'Wrong message size error';
  47.       EsockENOBUFS: ErrorMsg := 'No buffer space available error';
  48.       EsockENOTCONN: ErrorMsg := 'Not connected error';
  49.       EsockENOTSOCK: ErrorMsg := 'File descriptor is not a socket error';
  50.       EsockEPROTONOSUPPORT: ErrorMsg := 'Protocol not supported error';
  51.       EsockEWOULDBLOCK: ErrorMsg := 'Operation would block error';
  52.       else
  53.         ErrorMsg := 'Undescribed error : ' + IntToStr(socketerror);
  54.     end;
  55.     writeln(S, ErrorMsg);
  56.     halt(100);
  57.   end;
  58.  
  59. begin
  60.   SockDesc := fpSocket(AF_INET, SOCK_STREAM, 0);
  61.   if SockDesc = -1 then
  62.     Perror('[Server] Socket : ');
  63.   SockAddr.sin_family := AF_INET;
  64.   // Port 8008
  65.   SockAddr.sin_port := htons(8008);
  66.   // Look on all interfaces so address 0.0.0.0
  67.   SockAddr.sin_addr := StrToNetAddr('0.0.0.0');
  68.   // Bind socket
  69.   if fpBind(SockDesc, @SockAddr, sizeof(SockAddr)) = -1 then
  70.     PError('[Server] Bind : ');
  71.   // Turn socket into listening state
  72.   if fpListen(SockDesc, 1) = -1 then
  73.     PError('[Server] Listen : ');
  74.   // Waiting client connection
  75.   Writeln('Waiting for client connection, run now client in an other tty');
  76.   // Accept client connection
  77.   AddrSize := sizeof(ClientAddr);
  78.  
  79.   while True do
  80.   begin
  81.     clientId := fpAccept(SockDesc, @ClientAddr, @AddrSize);
  82.     if clientId = -1 then
  83.       PError('[Server] Accept : ' + NetAddrToStr(ClientAddr.sin_addr))
  84.     else
  85.       writeln('[Server] New client connected from: ' + NetAddrToStr(ClientAddr.sin_addr));
  86.     // Read data
  87.     RecvSize := fprecv(clientId, @Buffer, SizeOf(Buffer), 0);
  88.     Mensaje := Buffer;
  89.     while RecvSize > 0 do
  90.     begin
  91.       if RecvSize > 0 then
  92.         writeln('[Server] Receive : ' + Mensaje + ' [' + IntToStr(RecvSize) + ']');
  93.       RecvSize := fprecv(clientId, @Buffer, SizeOf(Buffer), 0);
  94.       Mensaje := Buffer;
  95.     end;
  96.     if (RecvSize = 0) and (SocketError = 0) then
  97.     begin
  98.       writeln('[Server] Client disconnect.');
  99.       writeln('');
  100.     end;
  101.     if RecvSize = -1 then
  102.       PError('[Server] Read failed : ');
  103.   end;
  104. end.            
  105.  

============
CLIENT:
Code: Pascal  [Select][+][-]
  1. program socket_client;
  2.  
  3. {
  4.   Program to test sockets and get working example of Sockets unit.
  5.   This is the client part. The server part must be start before using this one.
  6.   Inspired from fpConnect / fpAccept examples
  7. }
  8.  
  9. {$mode objfpc}{$H+}
  10.  
  11. uses
  12.   {$IFDEF UNIX}
  13.   cthreads,
  14.   {$ENDIF}
  15.   Classes,
  16.   Sockets,
  17.   SysUtils
  18.   { you can add units after this };
  19.  
  20.   procedure PError(const S: string);
  21.   var
  22.     ErrorMsg: string;
  23.   begin
  24.     case socketerror of
  25.       EsockADDRINUSE: ErrorMsg := 'Error number when socket address is already in use';
  26.       EsockEACCESS: ErrorMsg := 'Access forbidden error';
  27.       EsockEBADF: ErrorMsg := 'Alias: bad file descriptor';
  28.       EsockEFAULT: ErrorMsg := 'Alias: an error occurred';
  29.       EsockEINTR: ErrorMsg := 'Alias : operation interrupted';
  30.       EsockEINVAL: ErrorMsg := 'Alias: Invalid value specified';
  31.       EsockEMFILE: ErrorMsg := 'Error code ?';
  32.       EsockEMSGSIZE: ErrorMsg := 'Wrong message size error';
  33.       EsockENOBUFS: ErrorMsg := 'No buffer space available error';
  34.       EsockENOTCONN: ErrorMsg := 'Not connected error';
  35.       EsockENOTSOCK: ErrorMsg := 'File descriptor is not a socket error';
  36.       EsockEPROTONOSUPPORT: ErrorMsg := 'Protocol not supported error';
  37.       EsockEWOULDBLOCK: ErrorMsg := 'Operation would block error';
  38.       else
  39.         ErrorMsg := 'Undescribed error : ' + IntToStr(socketerror);
  40.     end;
  41.     writeln(S, ErrorMsg);
  42.   end;
  43.  
  44. var
  45.   // Socket descriptor
  46.   SockDesc: longint;
  47.   // Socket address
  48.   SockAddr: TInetSockAddr;
  49.   // Message
  50.   Buffer: array [1..20] of char;
  51.   //string[255];
  52.   i, j: longint;
  53.   Result: longint;
  54.  
  55.   Mensaje: string;
  56. begin
  57.   SockDesc := fpSocket(AF_INET, SOCK_STREAM, 0);
  58.   if SockDesc = -1 then
  59.     Perror('[Client] Socket : ');
  60.   SockAddr.sin_family := AF_INET;
  61.   // Port 8008
  62.   SockAddr.sin_port := htons(8008);
  63.   // Address 127.0.0.1
  64.   SockAddr.sin_addr := StrToNetAddr('127.0.0.1');
  65.   // Connection
  66.   if fpconnect(SockDesc, @SockAddr, SizeOf(SockAddr)) = -1 then
  67.     PError('[Client] Connect : ');
  68.   // Send data
  69.   i:=1;
  70.   writeln('send a "-", and the client will disconnect (exit).');
  71.   Mensaje := '(' + IntToStr(i) + ') >1st Msg.';
  72.   while copy(Mensaje,length(Mensaje),1) <> '-' do
  73.   begin
  74.     Buffer := Mensaje;
  75.     Result := fpsend(SockDesc, @Buffer, SizeOf(Buffer), 1);
  76.     writeln(Buffer + ' [TX=' + IntToStr(Result) + ' / Data=' + IntToStr(SizeOf(Buffer)) + ']');
  77.     if Result <> (SizeOf(Buffer)) then
  78.       PError('[ERROR Client] Send : ');
  79.     sleep(5);
  80.     i := i+1;
  81.     readln(Mensaje);
  82.     Mensaje := '(' + IntToStr(i) + ') >' + Mensaje;
  83.  
  84.   end;
  85.   writeln('>>> press ENTER to disconnet and EXIT.');
  86.   readln();
  87.   writeln('>bye!');
  88.   // Shutdown communication
  89.   if fpshutdown(SockDesc, 2) = -1 then
  90.     PError('[Client] Shutdown : ');
  91.   // Close socket
  92.   if CloseSocket(SockDesc) = -1 then
  93.     PError('[Client] Close : ');
  94.   sleep(2000);
  95. end.                      
  96.  
« Last Edit: December 02, 2023, 08:50:26 pm by arturogr »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6683
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
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

bytebites

  • Hero Member
  • *****
  • Posts: 639
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

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
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.

Or, just use proper code formatting using [ code ][ /code ] tags instead.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Warfley

  • Hero Member
  • *****
  • Posts: 1499
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

arturogr

  • Newbie
  • Posts: 5
Thanks to Warfley, MarkMLl and Bytebites users, the solution was to change from 1 to 0, the FLAG used at the fpsend function from the client program:

original FLAG in fpsend function:
Code: Pascal  [Select][+][-]
  1. .
  2. .
  3. .
  4. Result := fpsend(SockDesc, @Buffer, SizeOf(Buffer), 1);
  5. .
  6. .
  7. .

correct FLAG in fpsend function:
Code: Pascal  [Select][+][-]
  1. .
  2. .
  3. .
  4. Result := fpsend(SockDesc, @Buffer, SizeOf(Buffer), 0);
  5. .
  6. .
  7. .
  8.  

Thanks to MarkMLl and Remy Lebeau users, I used the [ code ] tags to improve my post in this forum.

Now, I just do not know how to mark this topic as [SOLVED].
« Last Edit: December 02, 2023, 10:36:29 am by arturogr »

dseligo

  • Hero Member
  • *****
  • Posts: 1220
Now, I just do not know how to mark this topic as [SOLVED].

Modify your first post and change Subject so it has [SOLVED] in front of it.

 

TinyPortal © 2005-2018