C++ 服务器无法通过套接字从 python 客户端读取我的消息
C++ server cannot read my message from python client via socket
我写了一个 python 客户端脚本来通过 tcp 向服务器发送消息。
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 12003
BUFFER_SIZE = 1024
MESSAGE = b"Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
print "received data:", data
服务器可以接收到我的数据,但是好像无法读取数据。日志信息复制如下。
I0328 21:45:24.493249 505 prset04.cpp:210] reading the message (3472609771221168177 bytes)
E0328 21:45:25.493088 505 prset04.cpp:162] unable to receive on socket
I0328 21:45:25.493285 505 prset04.cpp:215] echoing the message
E0328 21:45:25.493479 505 prset04.cpp:185] unable to send on socket
我认为 C++ 套接字模块和 python 之间可能有些不同。但我不知道那里出了什么问题,因为我不熟悉 C++ 和套接字。
任何想法或解释都会很有帮助!
谢谢
服务器代码:
static void OnClient(const int sk) {
size_t len;
char buf[1024];
// Read the message length.
if (!ReadBytes(sk, reinterpret_cast<char*>(&len), sizeof(len))) {
LOG(ERROR) << "unable to read message length";
return;
}
LOG(INFO) << "reading the message (" << len << " bytes" << ")";
// Read the message.
ReadBytes(sk, buf, len);
LOG(INFO) << "echoing the message";
// Echo the message.
WriteBytes(sk, buf, len);
}
static bool ReadBytes(const int sk, char* buf, const size_t n) {
char* ptr = buf;
while (ptr < buf + n) {
if (!SetReadTimeout(sk)) {
return false;
}
auto ret = recv(sk, ptr, ptr - buf + n, 0);
if (ret <= 0) {
LOG(ERROR) << "unable to receive on socket";
return false;
}
ptr += ret;
}
return true;
}
正如 Galik 指出的那样,您的 python 脚本不会发送任何长度的消息。当您的 C++ 服务器读取 4 个字节(如果您使用的是 64 位 linux,则为 8 个字节)并期望它们是消息的长度。
所以前 4 个字节是 "Hell" 哪种二进制形式将是您的服务器尝试读取的大量字节。
解决此问题 - 在您的 python 脚本中发送前 4 个字节作为消息长度。
此外,您还需要使用网络字节顺序(如果您打算坚持使用二进制)来确保正确读取字节。
使用 ntohl() 函数将网络字节序号转换为主机字节序号。
就像 Galik 已经说过的那样,Python 不会像您的程序所期望的那样在字符串之前发送字符串的长度。 C/C++ 也不会这样做。
如果您希望 Python 程序与您的 C 程序一起工作,您必须考虑几件事:
- 使用
struct
模块将您的字符串打包成需要的长度
- 打包字符串时使用网络字节顺序
- 您应该知道,像
size_t
这样的声明是依赖于体系结构的,并且在 64 位和 32 位体系结构之间有所不同。如果您希望它们在体系结构之间兼容,则可以使用固定大小的整数,例如 uint32_t
。
示例代码:
from struct import pack
message = "Hello World"
data = pack('!i%ds' % len(message), len(message), message))
如果您无法更改 C 代码以使用网络字节顺序,您的具体代码应如下所示:
from struct import pack
message = "Hello World"
data = pack('<Q%ds' % len(message), len(message), message))
<
= 使用小端字节顺序
Q
= 使用无符号 64 位整数(sizet_t
在 64 位架构上)
我写了一个 python 客户端脚本来通过 tcp 向服务器发送消息。
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 12003
BUFFER_SIZE = 1024
MESSAGE = b"Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
print "received data:", data
服务器可以接收到我的数据,但是好像无法读取数据。日志信息复制如下。
I0328 21:45:24.493249 505 prset04.cpp:210] reading the message (3472609771221168177 bytes)
E0328 21:45:25.493088 505 prset04.cpp:162] unable to receive on socket
I0328 21:45:25.493285 505 prset04.cpp:215] echoing the message
E0328 21:45:25.493479 505 prset04.cpp:185] unable to send on socket
我认为 C++ 套接字模块和 python 之间可能有些不同。但我不知道那里出了什么问题,因为我不熟悉 C++ 和套接字。
任何想法或解释都会很有帮助!
谢谢
服务器代码:
static void OnClient(const int sk) {
size_t len;
char buf[1024];
// Read the message length.
if (!ReadBytes(sk, reinterpret_cast<char*>(&len), sizeof(len))) {
LOG(ERROR) << "unable to read message length";
return;
}
LOG(INFO) << "reading the message (" << len << " bytes" << ")";
// Read the message.
ReadBytes(sk, buf, len);
LOG(INFO) << "echoing the message";
// Echo the message.
WriteBytes(sk, buf, len);
}
static bool ReadBytes(const int sk, char* buf, const size_t n) {
char* ptr = buf;
while (ptr < buf + n) {
if (!SetReadTimeout(sk)) {
return false;
}
auto ret = recv(sk, ptr, ptr - buf + n, 0);
if (ret <= 0) {
LOG(ERROR) << "unable to receive on socket";
return false;
}
ptr += ret;
}
return true;
}
正如 Galik 指出的那样,您的 python 脚本不会发送任何长度的消息。当您的 C++ 服务器读取 4 个字节(如果您使用的是 64 位 linux,则为 8 个字节)并期望它们是消息的长度。 所以前 4 个字节是 "Hell" 哪种二进制形式将是您的服务器尝试读取的大量字节。
解决此问题 - 在您的 python 脚本中发送前 4 个字节作为消息长度。 此外,您还需要使用网络字节顺序(如果您打算坚持使用二进制)来确保正确读取字节。 使用 ntohl() 函数将网络字节序号转换为主机字节序号。
就像 Galik 已经说过的那样,Python 不会像您的程序所期望的那样在字符串之前发送字符串的长度。 C/C++ 也不会这样做。
如果您希望 Python 程序与您的 C 程序一起工作,您必须考虑几件事:
- 使用
struct
模块将您的字符串打包成需要的长度 - 打包字符串时使用网络字节顺序
- 您应该知道,像
size_t
这样的声明是依赖于体系结构的,并且在 64 位和 32 位体系结构之间有所不同。如果您希望它们在体系结构之间兼容,则可以使用固定大小的整数,例如uint32_t
。
示例代码:
from struct import pack
message = "Hello World"
data = pack('!i%ds' % len(message), len(message), message))
如果您无法更改 C 代码以使用网络字节顺序,您的具体代码应如下所示:
from struct import pack
message = "Hello World"
data = pack('<Q%ds' % len(message), len(message), message))
<
= 使用小端字节顺序
Q
= 使用无符号 64 位整数(sizet_t
在 64 位架构上)