идентификатор сокета равен -1

#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. Я полагаю, что это не имеет никакого отношения, потому что, когда я комментирую закрытие (ы) в деструкторе, проблема остается.