-1

What is the right way of send/receive a integer value using native winsock in only one line, similar to C++ code below? i'm tried translate this, but not know if is right. Can someone help me please?

C++:

enum MyEnum { element01, element02 };
int width;

int SendInt(SOCKET sock, int i)
{
   return Send(sock, (char *) &i, sizeof(i), 0);
}

if(SendInt(sock, MyEnum::element01) <= 0) return;
if(SendInt(sock, 0) <= 0) return;
if(recv(sock, (char *) &width, sizeof(width), 0) <= 0) return;

Delphi:

type
  MyEnum = (element01, element02);

var
 Width: Integer;

function SendInt(S: TSocket; I: Integer): Integer;
begin
  Result := send(S, PAnsiChar(I)^, Length(IntToStr(I)), 0);
end;

if SendInt(Sock, Integer(MyEnum.element01)) <= 0 then Exit;
if SendInt(Sock, 0) <= 0 then Exit;
if recv(Sock, PAnsiChar(Width)^, Length(IntToStr(Width)), 0) <= 0 then Exit;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
FLASHCODER
  • 1
  • 7
  • 24
  • 1
    Puppet voting is prohibited on this site. You've had your accounts removed previously for this reason, unfortunately no lessons are taken... – Sertac Akyuz Apr 16 '19 at 13:27

2 Answers2

2

The call to send is wrong. You must supply an untyped buffer for the bytes to be sent, and the number of bytes. Absolutely no place for IntToStr here.

Result := send(S, I, SizeOf(I), 0);

And similarly for the call to recv.

if recv(Sock, Width, SizeOf(Width), 0) <= 0 then Exit;

It is idiomatic to use Ord() to obtain the ordinal value of a Delphi enumerated type, so Ord(MyEnum.element01) rather than Integer(MyEnum.element01), but the end result will be exactly the same.

Your code doesn't convert between host and network byte order. But then, neither does the C++ code.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
2

You use:

function SendInt(S: TSocket; I: Integer): Integer;
begin
  Result := send(S, PAnsiChar(I)^, Length(IntToStr(I)), 0);
end;

The second parameter of send() is an untyped const parameter, meaning you can pass anything that has an address, but casting the integer to a pointer and then dereferencing it is certainly not correct.

You can simply do this:

begin
  Result := send(S, I, SizeOf(I), 0);
end;

Although, you may have to change the endianness using htonl():

begin
  // I := htonl(I); ??
  Result := send(S, I, SizeOf(I), 0);
end;

You should try both alternatives and see what comes out of it. One of them is correct.

You should also pass the integer the same way using recv(). You may have to use ntohl() (the opposite of htonl()) after a recv() call:

function RecvInt(S: TSocket; var J: Integer): Integer;
begin
  Result := recv(S, J, SizeOf(J), 0);
  // J := ntohl(J); ??
end;
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • 1
    You are right about the endianness but of course the C++ code gets it wrong too. So using network order might result in the system failing. – David Heffernan Apr 15 '19 at 22:50
  • If both receiver and sender have the same endianness, then using *htonl* and *ntohl* is probably irrelevant. Otherwise, it isn't. After all, swapping order twice results in the original order again. – Rudy Velthuis Apr 15 '19 at 23:02
  • It is customary to always send multi-byte integers in big endian (network byte order), even if the sender and receiver are both little endian. You never know when a big endian party may be introduced into the system in the future. All binary Internet protocols have pretty much standardized on big endian for transmissions across machine boundaries. – Remy Lebeau Apr 15 '19 at 23:47
  • @Remy: I know. Hence htonl(). – Rudy Velthuis Apr 15 '19 at 23:53
  • You should replace at least one with exactly one. We three all know about network and host byte order. The real point here is thelat asker may not control both ends of the socket. If one end does it wrong then the other end has to also. If asker can fix both ends he should. – David Heffernan Apr 16 '19 at 05:44