C# 向 Python 发送整数

0 投票
2 回答
1181 浏览
提问于 2025-04-17 17:21

我正在尝试通过套接字技术,从一个在电脑上运行的C#程序(服务器)向一个在Linux机器上运行的Python客户端脚本发送两个整数。到目前为止,我只能发送字符串。

服务器代码是:

TcpListener listener = new TcpListener(IPAddress.Any, 12345);
Invoke(new PrintMsg(printMsg), new object[] { "Trying to connect" });
listener.Start();

for(; ; ;)
{
   TcpClient client = null;

   try
   {
      client = listener.AcceptTcpClient();
      netStream = client.GetStream();
      Invoke(new PrintMsg(printMsg), new object[] { "Found client" });


      //send command to client
      ASCIIEncoding encoder = new ASCIIEncoding();
      byte[] buffer = encoder.GetBytes("Hello client");
      netStream.Write(buffer, 0, buffer.Length);
      netStream.Flush();

   }

   catch (Exception ex)
   {
      Invoke(new PrintMsg(printMsg), new object[] { ex.ToString() });
   }
}

客户端代码是:

while True:
    msg = s.recv(1024)
    print 'SERVER:', msg

所以我想把一个整数“放入”一个缓冲数组中,然后发送给Python脚本。这可能吗?我哪里做错了?

2 个回答

2

在你解决“我怎么发送一个整数?”这个问题之前,首先要解决一个更大的问题:“我怎么发送一条消息?”

在TCP协议中,当你在一端调用send时,即使它一次性发送了整个数据包(这并不一定能保证),另一端可能会通过多次recv调用接收到数据,而不是一次性接收到所有数据。更糟糕的是,它可能在一次recv中接收到部分send的数据和下一次send的数据。

你可以使用一些更高级的协议,比如ZeroMQ,或者甚至HTTP,这些协议会为你处理这些问题。但如果你想直接使用原始的TCP协议,那就得自己处理这些事情。

一个明显的解决办法是使用分隔符,比如换行符(或者NUL字节等)——但这样的话,你需要有办法在消息中间转义换行符。另一种可能是使用某种头部信息来描述消息的其余部分,比如netstring。或者你可以使用像JSON这样的自我分隔消息类型。

很多非常简单的处理分隔符问题的方法,自动处理了整数的发送。JSON就把数字作为一种类型包含在内。或者你可以通过netstrings或者用换行符分隔的字符串来发送整数。

如果你真的想以某种“二进制”方式编码数字,你需要选择一种表示方式,并编写代码在两端进行转换。例如,如果你想限制为32位有符号整数,并以大端C整数格式发送,Python代码可以是buf = struct.pack('!I', number)number = struct.unpack('!I', buf)

但你应该考虑一下是否真的需要二进制格式。显然,作为人类,这种格式更难以阅读和调试。而且更容易出错(例如,忘记字节序或字长)。而且简单的方法也有限(例如,上面提到的!I格式对于超过大约20亿的数字会失败)。而且它不一定更紧凑。通常,你发送很多小数字,作为字符串带换行符时只需要2-3个字节,但以二进制形式则需要4个字节。

下面是一个简单的Python实现的基于行的数字读取器:

def read_numbers_off_socket(s):
    buf = ''
    while True:
        newbuf = s.recv(4096)
        if not newbuf:
            yield int(buf)
            break
        buf += newbuf
        lines = buf.split('\n')
        for line in lines[:-1]:
            yield int(line)

但你可以用s.makefile更简单地做到这一点:

def read_numbers_off_socket(s):
    with s.makefile() as f:
        for line in f:
            yield int(line)
2

从你的客户端代码来看,很难判断你用了什么样的客户端库来建立TCP连接。

为什么不试试一些支持C#和Python的消息队列实现,比如ZeroMQ呢?如果你需要在传递数据结构时更复杂一点,也可以考虑使用一些内存中的键值存储解决方案来实现队列,比如Redis。这样做的好处是,消息队列的服务器和客户端实现得很好,你只需要写一两行代码就能在你的业务逻辑中发送和接收消息。

撰写回答