Python 3套接字客户端发送数据和C++套接字服务器接收偏移数据?

Posted

技术标签:

【中文标题】Python 3套接字客户端发送数据和C++套接字服务器接收偏移数据?【英文标题】:Python 3 socket client sending data and C++ socket server receiving data with offset? 【发布时间】:2014-01-20 21:10:57 【问题描述】:

我做了一个小测试,将整数从 python 应用程序(客户端套接字)发送到 c++ 应用程序(套接字服务器),两者都是 TCP 流套接字。我还测试了将相同的整数从 python 中的客户端套接字发送到 python 中的服务器套接字。

我要做的是发送一个 4 个字节的数组(c++ 中的 char),每个 char 的整数右移(>>)像这样(python 语法):

...
[my_int >> i & 0xff for i in (24,16,8,0)]:
...

问题是当从 python 中的客户端套接字发送到 python 中的服务器套接字时,数据“正常到达”,例如,如果我发送整数 1390248303

python 服务器套接字首先打印接收到的字节流,然后为每个字节打印其 ascii 代码,然后我这样做:

sum([l[3-i] << 8*i for i in (3,2,1,0)])

“重建”整数,这是结果(没问题):

RECEIVED: b'R\xdd\x81o'
82
221
129
111
RECEIVED: 1390248303

但是 C++ 服务器套接字,我在其中做同样的事情,但在代码中更详细:

...
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);
...

输出

82
-35
-127
111
Received: 1373405551

你有没有看到中间的2个字节与python中服务器套接字输出的内容对应的中间2个字节不同?不仅如此,如果我向它们添加 256,它们就会变得相同:

 -35 + 256 = 221
-127 + 256 = 129

这种行为的原因是什么?提前感谢您的任何提示!

这是应用程序的代码:

python 客户端套接字:

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 服务器套接字:

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++ 服务器套接字:

#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;

【问题讨论】:

【参考方案1】:

msg[] 被声明为char,但不能保证为unsigned。使用unsigned char

两行

            printf("%d\n",msg[3-i]);
            term = msg[3-i];

转换为有符号整数。 %d 格式化为有符号整数,使用 %uterm 声明为 int,改为 unsigned int

【讨论】:

【参考方案2】:

根据@Ante 的建议,我更改了 C++ 服务器套接字中的代码,我还将 recvbuf 更改为 unsigned char 并将 sum 从 int 更改为 unsigned int 以保持一致性(毕竟我正在等待接收 unsigned char 并“重建”一个 unsigned int ) 但它也可以让 recvbuf 和 sum 保持原样。我离开评论了之前的内容。

问题在于,为了表示一个如此大的整数,我实际上使用的是无符号整数,并且发送的字节是 ascii 代码,其范围是 0 - 255(无符号字符的相同范围),字符范围是 -127 - 126.

尽管如此,套接字并不关心数据类型,它们只是发送二进制数据,所以我收到了无符号字符,当放入一个字符时,它们“溢出”并变为负数(从技术上讲,这是因为 two's complement 的工作方式我想想)。

关于更正代码的更多说明:

1) 这个

if (term < 0)
    term = 256 + term;

不再需要(实际上我是手动修复溢出的问题)。

2) 我必须使用 cast to char* (char ) 才能使用 recv、strncpy 和 send ,它们将 char 作为参数而不是 unsigned char* 。这项工作,我认为它不是 hackish,因为指向 char 的指针和指向 unsigned char 的指针都指向内存中具有相同大小(8 位)的数据类型。如果这是错误的或可能导致不需要或意外的行为,请纠正我。

    //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);

【讨论】:

以上是关于Python 3套接字客户端发送数据和C++套接字服务器接收偏移数据?的主要内容,如果未能解决你的问题,请参考以下文章

C++ Socket学习记录 -3

python套接字接收二进制数据

通过套接字在 C++ 和 python 之间交换固定浮点数组

C++ 套接字 Send() 线程安全

在 C++ 套接字编程中嵌入 Python

Python套接字客户端:发送数据和接收结果