以下是我正在处理的简单回显服务器,服务器将接受来自客户端的请求并返回客户端发送给它的请求。该程序适用于socat
,但在使用我自己的客户端时会冻结。
我的旧代码存在的问题是我使用read
而不是read_some
。 read
将阻塞管道,直到它读取特定数量的字节或获取损坏的管道异常,而read_some
将一次读取一个块。更新后的版本使用read_some
来读取输入流并检查程序读取的最后一个字符是\0
,如果它是\0
,则表示它到达命令的末尾,因此它将回声。这是有效的,因为我只传递字符串文字,管道中没有二进制数据。
服务器的代码是
using namespace std;
const char* epStr = "/tmp/socketDemo";
int main() {
namespace local = boost::asio::local;
boost::asio::io_service io_service;
::unlink(epStr);
local::stream_protocol::endpoint ep(epStr);
local::stream_protocol::acceptor acceptor(io_service, ep);
while(1) {
local::stream_protocol::socket *socket = new local::stream_protocol::socket(io_service);
acceptor.accept(*socket);
char buf[2048] = {0};
boost::system::error_code error;
size_t len = 0;
while(1) {
len += socket->read_some(boost::asio::buffer(buf + len, 2048 - len));
cout << "read " << len << endl;
if (buf[len] == '\0') {
break;
}
}
cout << "read " << len << " bytes" << endl;
cout << buf << endl;
boost::asio::write(*socket, boost::asio::buffer(buf, len), boost::asio::transfer_all());
}
}
使用socat
命令测试服务器时,例如
echo "12345" | socat - UNIX-CONNECT:/tmp/socketDemo
它将返回所需的结果。
我的客户端代码是
const char* epStr = "/tmp/socketDemo";
int main(int argc, const char* argv[]) {
boost::asio::io_service io_service;
boost::asio::local::stream_protocol::endpoint ep(epStr);
boost::asio::local::stream_protocol::socket socket(io_service);
socket.connect(ep);
boost::asio::write(socket, boost::asio::buffer(argv[1], strlen(argv[1])), boost::asio::transfer_all());
char buf[1024] = {0};
size_t len = 0;
while(1) {
len += socket.read_some(boost::asio::buffer(buf + len, 2048 - len));
std::cout << "read " << len << std::endl;
if (buf[len] == '\0') {
break;
}
}
std::cout << "read " << len << " bytes\n";
std::cout << buf << std::endl;
socket.close();
当执行客户端时,最初两者都没有输出,在我杀死客户端之后,服务器将输出它读取n个字节并获得一个损坏的管道异常。
这可能是由服务器中的read
函数引起的吗?如果是这样,有没有办法让它知道应该读取多少数据而不在每条消息的开头发送数据块的大小?我也想知道为什么socat
可以使用这个服务器没有任何问题?谢谢!
答案 0 :(得分:1)
我也想知道为什么socat可以在没有任何服务器的情况下使用这个服务器 问题
可能是因为socat关闭了套接字而你的客户没有。
如果是这样,有办法让它知道它应该读取多少数据 没有在每个开头发送数据块的大小 消息?
例如,假设您正在定义/使用包含EOM的协议,一次读取一个字节,直到您读取消息结束字符为止。