Вот простой эхо-сервер, над которым я работаю, сервер примет запрос от клиента и вернет то, что клиент отправляет на него. Программа отлично работает с 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
может работать с этим сервером без проблем? Спасибо!
Мне также интересно, почему socat может работать с этим сервером без каких-либо
проблема?
Возможно, потому что socat закрывает сокет, а ваш клиент — нет.
Если да, есть ли способ дать ему знать, сколько данных он должен прочитать
без отправки размера порции данных в начале каждого
сообщение?
Например, чтение одного байта за раз, пока вы не прочитаете символ конца сообщения, предполагая, что вы определяете / используете протокол, который включает EOM.
Других решений пока нет …