C# 向 Python 发送整数
我正在尝试通过套接字技术,从一个在电脑上运行的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 个回答
在你解决“我怎么发送一个整数?”这个问题之前,首先要解决一个更大的问题:“我怎么发送一条消息?”
在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)
从你的客户端代码来看,很难判断你用了什么样的客户端库来建立TCP连接。
为什么不试试一些支持C#和Python的消息队列实现,比如ZeroMQ呢?如果你需要在传递数据结构时更复杂一点,也可以考虑使用一些内存中的键值存储解决方案来实现队列,比如Redis。这样做的好处是,消息队列的服务器和客户端实现得很好,你只需要写一两行代码就能在你的业务逻辑中发送和接收消息。