I have made a small test to send an integer from a python application (client socket) to a c++ application (socket server) both are TCP stream sockets. I have also tested sending the same integer from the client socket in python to a server socket in python.
What I do is I send an array of 4 bytes (char in c++), each char has the integer shifted right (>>) like this (python syntax):
...
[my_int >> i & 0xff for i in (24,16,8,0)]:
...
The problem is that when sending from the client socket in python to the server socket in python the data "arrives ok", for instance if I send the integer 1390248303
the python server socket first prints the bytes stream received then for each byte it prints its ascii code and then I do:
sum([l[3-i] << 8*i for i in (3,2,1,0)])
to "rebuild" the integer and this is the result (which is ok):
RECEIVED: b'R\xdd\x81o'
82
221
129
111
RECEIVED: 1390248303
BUT the C++ server socket, in which I do the same but with more verbose in the code:
...
int sum = 0;
int term = 0;
for(int i = 3;i > -1;i--)
{
printf("%d\n",msg[3-i]);
term = msg[3-i];
//if (term < 0)
// term = 256 + term;
suma += term << 8*i;
};
printf("Received: %d\n",sum);
...
Outputs
82
-35
-127
111
Received: 1373405551
Did you see that the 2 bytes in the middle are different to the 2 bytes in the middle corresponding to what the server socket in python outputs? Not only that but if I add 256 to them they became the same:
-35 + 256 = 221
-127 + 256 = 129
What is the reason of this behaviour? Thanks beforehand for any hint!
Here is the code of the applications:
python client socket:
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("localhost", 7000))
my_int = 1390248303
my_bytes = bytearray()
for e in [my_int >> i & 0xff for i in (24,16,8,0)]:
my_bytes.append(e)
print("To be sent:", my_bytes)
client_socket.send(my_bytes)
print("Sent:", my_bytes)
client_socket.close()
python server socket:
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 7000))
server_socket.listen(5)
print("TCPServer Waiting for client on port 7000")
while 1:
client_socket, address = server_socket.accept()
print("I got a connection from ", address)
while 1:
data = client_socket.recv(32)
print("RECEIVED:",data)
l = []
for e in data:
l.append(e)
print(e)
print("RECEIVED:",sum([l[3-i] << 8*i for i in (3,2,1,0)]))
if (data == b''):
break;
break;
C++ server socket:
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_PORT "7000"
//"27015"
#define DEFAULT_BUFFER_LENGTH 32
//512
int main() {
WSADATA wsaData;
// Initialize Winsock
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
struct addrinfo *result = NULL,
hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // Internet address family is unspecified so that either an IPv6 or IPv4 address can be returned
hints.ai_socktype = SOCK_STREAM; // Requests the socket type to be a stream socket for the TCP protocol
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the local address and port to be used by the server
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0)
{
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET ListenSocket = INVALID_SOCKET;
// Create a SOCKET for the server to listen for client connections
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed: %d", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
// To listen on a socket
if ( listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
printf("listen failed: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
SOCKET ClientSocket;
ClientSocket = INVALID_SOCKET;
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char recvbuf[DEFAULT_BUFFER_LENGTH];
int iSendResult;
// receive until the client shutdown the connection
do {
iResult = recv(ClientSocket, recvbuf, DEFAULT_BUFFER_LENGTH, 0);
if (iResult > 0)
{
char msg[DEFAULT_BUFFER_LENGTH];
memset(&msg, 0, sizeof(msg));
strncpy(msg, recvbuf, iResult);
printf("Received: %s\n", msg);
//Here is where I implement the python code:
//sum([l[3-i] << 8*i for i in (3,2,1,0)]));
int sum = 0;
int term = 0;
for(int i = 3;i > -1;i--)
{
printf("%d\n",msg[3-i]);
term = msg[3-i];
//if (term < 0)
// term = 256 + term;
sum += term << 8*i;
};
printf("Received: %d\n",sum);
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
getchar();
return 1;
}
printf("Bytes sent: %ld\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closed\n");
else
{
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
getchar();
return 1;
}
} while (iResult > 0);
// Free the resouces
closesocket(ListenSocket);
WSACleanup();
getchar();
//while (true){};
return 0;
}
msg[]
is declared as char
which is not guaranteed to be unsigned . Use unsigned char
.
Both of lines
printf("%d\n",msg[3-i]);
term = msg[3-i];
cast to signed integer. %d
formats to signed integer, use %u
. term
is declared as int
, make it unsigned int
.
Following @Ante advices, I changed the code in C++ server socket, I also changed recvbuf to unsigned char and sum from int to unsigned int for consistency (after all I am waiting to receiving unsigned chars and "rebuild" an unsigned int) but it also worked leaving both recvbuf and sum as they were. I left commented what was before.
The problem was that for representing an integer so big I was actually using an unsigned integer and the bytes that were being sent were ascii codes whose range is 0 - 255 (the same range of unsigned char) and char range is -127 - 126.
Nevertheless, sockets do not care about data types, they just send binary data so I was receiveng unsigned chars that when bein put in a char they "overflow" and go negative (technically it is because of how two's complement works I think).
A few more notes about the corrected code:
1) This
if (term < 0)
term = 256 + term;
is no longer necessary (actually I was fixing manually the issue of the overflow).
2) I had to use cast to char* (char ) in order to be able to use recv,strncpy and send which take char as parameters not unsigned char* . This work and I think it is not hackish because both a pointer to char and a pointer to unsigned char point to a datatype with the same size in memory (8 bits). If this is wrong or could lead to unwanted or unexpected behaviour please correct me.
//char recvbuf[DEFAULT_BUFFER_LENGTH];
unsigned char recvbuf[DEFAULT_BUFFER_LENGTH];
int iSendResult;
// receive until the client shutdown the connection
do {
//iResult = recv(ClientSocket, recvbuf, DEFAULT_BUFFER_LENGTH, 0);
iResult = recv(ClientSocket, (char *)recvbuf, DEFAULT_BUFFER_LENGTH, 0);
if (iResult > 0)
{
//char msg[DEFAULT_BUFFER_LENGTH];
unsigned char msg[DEFAULT_BUFFER_LENGTH];
memset(&msg, 0, sizeof(msg));
//strncpy((msg, recvbuf, iResult);
strncpy((char *)msg, (char *)recvbuf, iResult);
printf("Received: %s\n", msg);
//sum([l[3-i] << 8*i for i in (3,2,1,0)]));
//int sum = 0;
unsigned int sum = 0;
//int term = 0;
unsigned int term = 0;
for(int i = 3;i > -1;i--)
{
//printf("%d\n",msg[3-i]);
printf("%u\n",msg[3-i]);
term = msg[3-i];
sum += term << 8*i;
};
//printf("Received: %d\n",sum);
printf("Received: %u\n",sum);
//iSendResult = send(ClientSocket, recvbuf, iResult, 0);
iSendResult = send(ClientSocket, (char *) recvbuf, iResult, 0);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.