简体   繁体   English

使用从Python(客户端)到C ++(服务器)阵列的套接字发送数据

[英]Sending data using socket from Python(client) to C++(server) arrays

I have been attempting to send an array from Python to C++ using a socket however have kept running into issues. 我一直在尝试使用套接字将数组从Python发送到C ++但是仍然遇到问题。

Python side there are issues sending an array directly such as pickle not being compatible with C++, as such the only semi-reliable method I have found is sending it as a string: Python方面存在直接发送数组的问题,例如pickle与C ++不兼容,因此我发现的唯一半可靠方法是将其作为字符串发送:

import socket
import sys
import random

# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = ('localhost', 5555)
print >>sys.stderr, 'connecting to %s port %s' % server_address
sock.connect(server_address)

# Message to be sent to C++
# message = [random.randint(1, 10),random.randint(1, 10),random.randint(1, 10)]
i = 0

while i < 5:
    a_converted = (random.randint(1,255), random.randint(1,255), random.randint(1,255))
    #a_converted = 'words'

    print a_converted
    # Sending message to C++
    sock.sendall(str(a_converted))
    i += 1

sock.close()

The issue with sending it as a string is that I actually require it as an double style array on the other side. 将其作为字符串发送的问题是我实际上需要它作为另一侧的双样式数组。 The C++ code I have is currently the following: 我目前的C ++代码如下:

#include "stdafx.h"
#include <iostream>
#include <winsock2.h>
#include <WS2tcpip.h> //for SOCKET communication
#include <sstream>
#include <stdlib.h>

//Linking Ws2_32.lib, Mswsock.lib, Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#pragma warning(disable:4996)//to disable warning message

using namespace std;

int main()
{
    WSADATA WSAData;

    SOCKET server, client;

    SOCKADDR_IN serverAddr, clientAddr;

    WSAStartup(MAKEWORD(2, 0), &WSAData);
    server = socket(AF_INET, SOCK_STREAM, 0);

    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(5555);
    ::bind(server, (SOCKADDR *)&serverAddr, sizeof(serverAddr));
    listen(server, 0);

    cout << "Listening for incoming connections..." << endl;

    string a_converted[1000];

    int clientAddrSize = sizeof(clientAddr);
    if ((client = accept(server, (SOCKADDR *)&clientAddr, &clientAddrSize)) != INVALID_SOCKET)
    {
        cout << "Client connected!" << endl;
        // Loop 
        int i = 0;

        while (i<5) {

            recv(client, (char*)a_converted, sizeof(a_converted), 0);

            char char_array[sizeof(a_converted)];

            strcpy(char_array, (char*)a_converted);
            memset(a_converted, 0, sizeof(a_converted));
            cout << "Client says: " << char_array << endl; 
            cout << endl;

            i = i++;

        }
        closesocket(client);
        WSACleanup();
        cout << "Client disconnected." << endl;
    }
    cout << "Press Enter to continue" << endl;
    getchar();
}

The information is received and correct but I have been unable to correctly convert the data. 收到的信息是正确的,但我无法正确转换数据。 I have tried to use atof and similar functions to convert on the C++ side but the presence of commas and brackets from the Python side seem to result in it erroring and giving zeros and I've had little luck trying to remove them from the string. 我试图使用atof和类似的函数在C ++端进行转换,但是Python端的逗号和括号的出现似乎导致它出错并给出了零,并且我没有尝试从字符串中删除它们。

I can't help but think there must be a better way of doing this but I am really new to coding so would not be surprised if I am overlooking something. 我不能不认为必须有一个更好的方法来做这个,但我真的很新编码所以如果我忽略了一些东西就不会感到惊讶。 I would appreciate either an explanation of how to send an array directly that C++ can read from Python or a way to convert the string it sends in C++. 我要感谢如何直接发送C ++可以从Python读取的数组或者转换它在C ++中发送的字符串的方法。

The most straight-forward way to accomplish this is to employ python's struct module to encode your array into a binary format that will be convenient to receive in C++. 实现这一目标的最直接的方法是使用python的struct模块将您的数组编码为二进制格式,便于在C ++中接收。

For example, to send an array of 32-bit integers, you might do something like this: 例如,要发送32位整数数组,您可能会执行以下操作:

import struct

def encode_int_array(int_list):
    buf = struct.pack("!I" + "I" * len(int_list), len(int_list), *int_list)
    return buf

Explanation: The ! 说明: ! character specifies the byte-ordering to be used in the encoding (here, big-endian / "network" order), the I character is used here for the array length, then again once for each integer to be encoded. character指定要在编码中使用的字节顺序(此处为big-endian /“network”顺序),此处使用I字符表示数组长度,然后再对每个要编码的整数使用一次。 The actual array length and each integer is then packed. 然后打包实际的数组长度和每个整数。

So, if you called this function with the list [1, 2, 3] , the format string given to pack will be "!IIII" and the the remaining arguments will be 3, 1, 2, 3 (the first '3' being the array length to encode). 所以,如果你调用列表此功能[1, 2, 3]格式字符串给pack"!IIII"而其余的参数将是3, 1, 2, 3 (第一个“3”是要编码的数组长度)。 The end result is a bytes string containing the encoded 32-bit (4-byte) integers: 最终结果是包含编码的32位(4字节)整数的bytes字符串:

|ArrayLen|Integer0|Integer1|Integer2|....

Use the above along with sendall to transmit the resulting buffer: 使用上面的sendall传输结果缓冲区:

sock.sendall(encode_int_array(
    [random.randint(1,255), random.randint(1,255), random.randint(1,255)]))

On the C++ side, first read 4 bytes (to get the array length), convert the array length to native byte ordering, then read an additional 4 * array-length bytes to get all the integers; 在C ++方面,首先读取4个字节(以获得数组长度),将数组长度转换为本机字节排序,然后读取另外的4 *数组长度字节以获得所有整数; then convert each of those to native byte order. 然后将每个转换为本机字节顺序。 You should be careful never to assume that recv will receive all of the data you want. 您应该小心,不要假设recv将接收您想要的所有数据。 The SOCK_STREAM semantics do not guarantee that. SOCK_STREAM语义不保证。 So you need to ensure you receive exactly the number you expected. 因此,您需要确保收到预期的数字。

The C++ side might look something like this: C ++方面看起来像这样:

#include <cstdint>  // uint32_t et al definitions

// Function to receive exactly "len" bytes.
// Returns number of bytes received, or -1 on EOF or error
int recv_all(int sock, char *buf, unsigned int len)
{
    unsigned int n = 0;
    int status;
    while (n < len) {
        status = recv(sock, buf + n, len - n);
        if (status == 0) {
            // Unexpected End of File
            return -1; // Or whatever
        } else if (status < 0) {
            // Error
            return -1; // Need to look at errno to find out what happened
        } else {
            n += status;
        }
     }
     return (int)n;
}

...
int status;
// Receive array length from client
uint32_t array_len;
status = recv_all(client, reinterpret_cast<char *>(&array_len), sizeof array_len);
if (status < 0) {
    // handle error
}

array_len = ntohl(array_len); // Convert length to native byte order

// Receive array contents from client
uint32_t int_array[array_len];
status = recv_all(client, reinterpret_cast<char *>(&int_array[0]), sizeof int_array);
if (status < 0) {
    // handle error
}
for (unsigned int n = 0; n < array_len; ++n)
    int_array[n] = ntohl(int_array[n]); // Convert to native byte order

(If you only wanted to send single byte integers, substitute 'B' for 'I' in the pack calls above, and the C++ below will also need to be adjusted accordingly -- with uint8_t in place of uint32_t , say.) (如果你只想发送单字节整数,在上面的pack调用中用'B'代替'I' ,下面的C ++也需要相应调整 - 比如uint8_t代替uint32_t 。)

This sounds like a serialization problem. 这听起来像是序列化问题。 As you want to connect two different languages, I suggest a standardized, well known format like JSON or XML. 由于您想连接两种不同的语言,我建议使用标准化的,众所周知的格式,如JSON或XML。 There are lots of libraries for converting JSON or XML into objects and vice versa. 有许多用于将JSON或XML转换为对象的库,反之亦然。

Ultimate, dead-end solution is, to pack the data into a binary file and send this over the socket. 最终的死端解决方案是将数据打包成二进制文件并通过套接字发送。 Try external libraries for JSON or XML first 首先尝试外部库的JSON或XML

Edit: 编辑:

JSON describes (in a very simple way), how objects can be saved as text (serialization). JSON(以非常简单的方式)描述了如何将对象保存为文本(序列化)。 It is as simple as 它很简单

{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 27,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    },
    {
      "type": "mobile",
      "number": "123 456-7890"
    }
  ],
  "children": [],
  "spouse": null
}

(taken from https://en.wikipedia.org/wiki/JSON ) (摘自https://en.wikipedia.org/wiki/JSON

You can imagine, it is a very straight forward process to read from the text to an object again (deserialization). 您可以想象,从文本再次读取对象(反序列化)是一个非常简单的过程。 There are libraries there which will do the job for you. 那里有图书馆可以为你完成这项工作。 This means for your project: 这意味着您的项目:

  • find a python JSON library which serializes your objects into JSON format 找到一个python JSON库,它将您的对象序列化为JSON格式
  • find a c++ JSON library which deserializes your data to an object 找到一个cSQL JSON库,它可以将数据反序列化为对象

I have seen this in use, as every data type is treated as a string to send it, and on the deserialization side, you need to decice for each case which data type it really is (converting the string to double or int or float or bool etc..) 我已经看到这个在使用中,因为每个数据类型都被视为一个字符串来发送它,并且在反序列化方面,你需要为每种情况确定它实际上是哪种数据类型(将字符串转换为double或int或float或者布尔等...)

You need to convert String in python to Bytes while 您需要将python中的String转换为Bytes while

sock.sendall sock.sendall

Refer Python: convert string to byte array 参考Python:将字符串转换为字节数组

Based on your python syntax, it should be python 2. 根据你的python语法,它应该是python 2。

Python 3 can easily find and insist to convert into Bytes while sendall. Python 3可以很容易地找到并坚持在sendall时转换为Bytes。

In python 2, you can use bytearray like 在python 2中,你可以像使用bytearray一样

sock.sendall (bytearray(str(a_converted))) sock.sendall(bytearray(str(a_converted)))

In python 3, you can call encode which defaults to UTF-8 while converting to bytes. 在python 3中,您可以在转换为字节时调用默认为UTF-8的encode。

sock.sendall (str(a_converted).encode()) sock.sendall(str(a_converted).encode())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过套接字从C ++服务器向Python客户端发送数据时出现问题 - Problem sending data over socket from C++ server to Python client Python 3套接字客户端发送数据,而C ++套接字服务器接收带偏移量的数据? - Python 3 socket client sending data and C++ socket server receiving data with offset? 如何将从 C++ 客户端套接字接收的二进制数据转换为 python 服务器套接字 - How can I convert binary data received from C++ client socket to python Server socket 使用python中的套接字编程将视频流从服务器发送到客户端 - sending video stream from server to client using socket programming in python 使用套接字python从客户端向服务器发送图像 - sending images from client to server using socket python 如何使用 Python 将数据从客户端套接字发送到服务器套接字? - How to send data from client socket to server socket using Python? 从python中的服务器发送一些行到QT(C ++)客户端 - Sending some lines from server in python to QT(C++) client 使用套接字将 GPS 数据从跟踪器发送到 python 服务器 - Sending the gps data from the tracker to python server using socket 将图像从套接字服务器(java)发送到套接字客户端(python) - sending Image from Socket server (java) to socket client (python) python 套接字将数据从客户端发送到服务器 - python socket send data from client to server
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM