#c #network-programming #protocol-buffers
#c #сетевое программирование #протокол-буферы
Вопрос:
Каким-то образом сокет равен -1. Это не должно быть связано с тем, что моя клиентская программа подключается и отправляет информацию, но останавливается сигналом SIGPIPE. Когда я отлаживаю сервер, я вижу, что accept возвращает значение -1. Я понятия не имею, почему. Если нет, ответьте, пожалуйста.
client.cpp
using namespace std;
using namespace msg;
using namespace dataExchange;
int main() {
Connection con("127.0.0.1", 123456);
Annoucement ann;
ann.set_typ(Annoucement::AKCJA);
con.send(ann);
}
server.cpp
using namespace std;
using namespace msg;
using namespace dataExchange;
int main() {
Server server(123456);
while(1) {
Connection con = server.accept();
Annoucement ann = con.receive();
cout << ann.typ() << endl;
}
}
connect.cpp
using namespace msg;
using namespace google::protobuf;
using namespace google::protobuf::io;
namespace dataExchange {
class SocketMaintenance {
protected:
sockaddr_in addr;
int s;
public:
SocketMaintenance(const unsigned int port) {
memset(amp;addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
s = socket(AF_INET, SOCK_STREAM, 0);
}
SocketMaintenance(const sockaddr_in Addr, const int Socket) {
addr = Addr;
s = Socket;
}
SocketMaintenance(const SocketMaintenanceamp; source) {
addr = source.addr;
s = source.s;
}
~SocketMaintenance() {
close(s);
}
void write(const char* buffer, const int n) {
::write(s, buffer, n);
}
};
class Connection : public SocketMaintenance {
FileOutputStream* raw_output;
FileInputStream* raw_input;
char buffer[1024];
public:
Connection(const char* IP, const unsigned int port) : SocketMaintenance(port) {
if(inet_pton(AF_INET, IP, amp;addr.sin_addr)<=0) {
throw WrongAddress();
}
if(connect(s, (sockaddr*)amp;addr, sizeof(addr))<0) {
throw ConnectFailed();
}
raw_output = new FileOutputStream(s);
raw_input = new FileInputStream(s);
}
Connection(const SocketMaintenanceamp; source) : SocketMaintenance(source) {}
~Connection() {
delete raw_output;
}
void send(const Messageamp; msg) throw(EmptyMessage) {
CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
int n = msg.ByteSize();
if(n<=0) throw EmptyMessage();
coded_output->WriteVarint32(n);
delete coded_output;
raw_output->Flush();
msg.SerializeToArray(buffer, n);
SocketMaintenance::write(buffer, n);
}
Annoucement receive() throw() {
CodedInputStream* coded_input = new CodedInputStream(raw_input);
google::protobuf::uint32 n;
coded_input->ReadVarint32(amp;n);
char *b;
int m;
coded_input->GetDirectBufferPointer((const void**)amp;b, amp;m);
Annoucement ann;
ann.ParseFromArray(b, n);
return ann;
}
};
class Server : public SocketMaintenance {
public:
Server(const unsigned int port) : SocketMaintenance(port) {
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(s, (struct sockaddr *)amp;addr, sizeof(addr))<0) {
throw BindFailed();
}
if(listen(s, 5)<0) {
throw ListenFailed();
}
}
Connection accept() throw() {
sockaddr_in client;
socklen_t client_len;
int client_socket = ::accept(s, (sockaddr*)amp;client, amp;client_len);
return Connection(SocketMaintenance(client, client_socket));
}
};
}
Я протестировал этот код, прежде чем разбил его на классы. Затем это сработало безупречно.
Ответ №1:
Одна из вопиющих проблем, которую я вижу, заключается в том, что ваш порт недействителен. sockaddr_in::sin_port
является uint16_t
, наибольшее значение которого может быть 65536. В лучшем случае вы усекаете свой порт при вызове htons
, что должно привести к 57920.
Что касается причины сбоя accept, -1
указывает на ошибку, и вы должны проверить значение errno
, чтобы понять, почему.
От man 2 accept
:
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ При успешном выполнении accept() возвращает неотрицательное целое число, которое является дескриптором принятого сокета. При ошибке возвращается значение -1, и значение errno устанавливается соответствующим образом.
Комментарии:
1. значение errno равно 22 — недопустимый аргумент. Аргумент сокета был равен 5. Не знаю, что не так :/
2. socklen_t client_len = sizeof(клиент); это нормально. Спасибо за информацию. Я новичок.
Ответ №2:
Как я предполагаю, где-то там вы передаете объект класса сокета по значению, а его деструктор преждевременно закрывает сокет. Я не мог побеспокоиться о том, чтобы просмотреть код, чтобы выяснить, так ли это, но некоторые наблюдения:
- не выделяйте вещи с помощью new, если вам абсолютно не нужно
- не внедряйте конструкторы копирования, если все, что они делают, — это то, что должен делать конструктор копирования по умолчанию
- Предотвратите копирование объектов сокета, объявив конструкторы копирования и операторы присваивания закрытыми, а затем не реализуйте их
- не «переставляйте» вещи в классы — либо начинайте писать классы с самого начала, либо просто пишите процедурный код
Комментарии:
1. Я полагаю, что это не имеет никакого отношения, потому что, когда я комментирую закрытие (ы) в деструкторе, проблема остается.