【问题标题】:Send/receive data through socket using python and ctype Structure使用python和ctype结构通过socket发送/接收数据
【发布时间】:2014-10-27 06:03:46
【问题描述】:

我正在尝试从 python 客户端向服务器发送和接收 C 结构数据,反之亦然。客户端和服务器都可以顺利地连接和交换数据。客户端向服务器发送一个 ctype 结构,服务器再次将其发回。问题是我不知道如何解释客户端收到的消息并提取结构格式的数据。我的最终想法是让 python 服务器和 C 客户端相互通信并以预定义的结构交换数据。

这是我在 Python 中用于客户端和服务器的代码:

客户端代码

import socket
import sys
import time

from ctypes import *

class payload_t(Structure):
    _fields_ = [("ms", c_ulong),
                ("counter", c_ulong),
                ("DHT_temperature", c_float),
                ("DHT_humidity", c_float),
                ("DS_temperature", c_float),
                ("temperature_setpoint", c_float),
                ("time_setpoint", c_float)]

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

# Connect the socket to the port where the server is listening
server_address = ('localhost', 10000)
print >>sys.stderr, 'connecting to %s port %s' % server_address
sock.connect(server_address)

try:
    for i in range(0,10):
        # Send data
        payload=payload_t(i*1000,i+1,25.2,45.7,25.8,33.22,3600.0)
        message = payload
        # 'This is the message.  It will be repeated.'
        print 'length of message %d' % sizeof(message)
        print 'sending "', message.ms, message.counter, message.DHT_temperature, message.DHT_humidity, message.DS_temperature, message.temperature_setpoint, message.time_setpoint, '"'
        sock.sendall(message)
        # time.sleep(0.1)
        # Look for the response
        amount_received = 0
        amount_expected = sizeof(message)

        while amount_received < amount_expected:
            datap = sock.recv(sizeof(message))
            amount_received += len(datap)
        print >>sys.stderr, 'received "%s"' % datap
        print type(datap)
        payload=payload_t()
        datap.readinto(payload)
        data=datap.readinto(payload_t)
        data=struct.unpack(payload_t,datap)
            print 'Received "', data.ms, data.counter, data.DHT_temperature, data.DHT_humidity, data.DS_temperature, data.temperature_setpoint, data.time_setpoint, '"'

finally:
    print >>sys.stderr, 'closing socket'
    sock.close()

服务器代码

import socket
import sys
from ctypes import *

class payload_t(Structure):
    _fields_ = [("ms", c_ulong),
                ("counter", c_ulong),
                ("DHT_temperature", c_float),
                ("DHT_humidity", c_float),
                ("DS_temperature", c_float),
                ("temperature_setpoint", c_float),
                ("time_setpoint", c_float)]

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

# Bind the socket to the port
server_address = ('localhost', 10000)
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)

# Listen for incoming connections
sock.listen(1)
payload=payload_t(0,0,0.0,0.0,0.0,0.0,0.0)
while True:
    # Wait for a connection
    print >>sys.stderr, 'waiting for a connection'
    connection, client_address = sock.accept()

    try:
        print >>sys.stderr, 'connection from', client_address

        # Receive the data in small chunks and retransmit it
        while True:
            data = connection.recv(sizeof(payload))
            print >>sys.stderr, 'received "%s"' % data
            if data:
                print >>sys.stderr, 'sending data back to the client'
                connection.sendall(data)
            else:
                print >>sys.stderr, 'no more data from', client_address
                break

    finally:
        # Clean up the connection
        connection.close()

【问题讨论】:

    标签: python structure ctype


    【解决方案1】:

    首先,您当前正在转储接收到的数据。您在每次循环迭代中重新分配变量“datap”。

    改为这样做:

    datap += sock.recv(sizeof(message) - amount_received)
    

    (当然这不是最有效的代码,但你明白了。)

    当您在“datap”变量中组装好结构后,您可以使用“from_buffer”或“from_buffer_copy”方法将其加载到您的 ctype 类中。

    payload = payload_t.from_buffer_copy(datap)
    

    在您的情况下后者更好,因为当您重新绑定“datap”变量时,您的缓冲区可能会消失。

    【讨论】:

    • 谢谢!它确实工作得很好。此外,很明显,我只需要在每一步都初始化有效载荷。
    【解决方案2】:

    直接通过调用recv_into 提供一个ctypes.Structure 实例怎么样?

    这是您的服务器代码的修改版本,希望我没有删除您想要保留的功能

    import socket
    import sys
    from ctypes import *
    
    class payload_t(Structure):
        _fields_ = [("ms", c_ulong),
                    ("counter", c_ulong),
                    ("DHT_temperature", c_float),
                    ("DHT_humidity", c_float),
                    ("DS_temperature", c_float),
                    ("temperature_setpoint", c_float),
                    ("time_setpoint", c_float)]
    
    # Create a TCP/IP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # Bind the socket to the port
    server_address = ('localhost', 10000)
    print >>sys.stderr, 'starting up on %s port %s' % server_address
    sock.bind(server_address)
    
    # Listen for incoming connections
    sock.listen(1)
    payload=payload_t()
    while True:
        # Wait for a connection
        print >>sys.stderr, 'waiting for a connection'
        connection, client_address = sock.accept()
    
        try:
            print >>sys.stderr, 'connection from', client_address
    
            # Receive the data in small chunks and retransmit it
            while True:
                data = connection.recv_into(payload)
                print >>sys.stderr, 'received "%s"' % data
                if data:
                    print >>sys.stderr, 'sending data back to the client'
                    print >>sys.stderr, 'time_setpoint "%f"' % payload.time_setpoint
                    connection.sendall(payload)
                else:
                    print >>sys.stderr, 'no more data from', client_address
                    break
    
        finally:
            # Clean up the connection
            connection.close()
    

    所以,基本上,我唯一做的就是使用 socket.recv_into 直接调用你的结构实例: https://docs.python.org/3/library/socket.html#socket.recv_into

    这让我之后可以直接访问结构属性。

    我猜这个结构足够小(28 个八位字节),因此数据适合单个 recv_into 调用。如果您需要多次调用 recv_into 来构建完整的结构,那么...

    如果您有 python 3.7,您可以使用切片内存视图对您的结构进行多次调用:

    mv = memoryview(payload).cast('B')
    size = sizeof(payload)
    while size > 0:
        data = connection.recv_into(mv) 
        mv = mv[data:] 
        size -= data 
    

    没有什么可以保证是诚实的。在早期版本的 Python 中,尝试在 memoryview 上强制转换“B”时可能会出现异常。回想一下 ctypes.Structure 上的 memoryview 是 0-dim,然后几乎不可能在没有演员表的情况下对其进行切片...

    【讨论】:

    • 是的,那怎么样?您能否进一步解释一下这如何解决问题?
    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 2023-04-11
    • 1970-01-01
    相关资源
    最近更新 更多