Haciendo un chat por sockets

Iniciado por ipmicrobious, 3 Diciembre 2016, 14:22 PM

0 Miembros y 1 Visitante están viendo este tema.

ipmicrobious

El principal problema que nos surge es que no logro hacer un sendto y un receivefrom del socket declarados, el valor de result nos sale de -1, dando error en el sendto por no enviarse correctamente.

¿Entendéis a qué se debe el fallo?, me he quedado trabado...

Por aquí tenéis el main...

#include "socket.hpp"

sockaddr_in make_ip_address(const std::string& ip_address, int port){

  uint32_t ip_b = atoi(ip_address.c_str());

  sockaddr_in local_address{}; // Porque se recomienda inicializar a 0
  local_address.sin_family = AF_INET;
  local_address.sin_addr.s_addr = htonl(ip_b); //Para escuchar por todas las direcciones IP de nuestra máquina.
  local_address.sin_port = htons(port); // Escogemos 0 para que el sistema operativo asigne un puerto cualquiera que esté disponible

  /* Hemos hecho uso de htonl() y htons() para convertir enteros de 32 o de 16 bits [como el número de puerto] del orden de
  bytes usado por nuestra CPU al que espera la interfaz de comunicaciones*/

  return local_address;

}

int main(int argc, char* argv[]){

  //Mensaje del socket local hacia el remoto - Prueba
  string message_text("¡Hola, mundo!");

  //Dirección del socket local
  string direccion_ip = "0.0.0.0";
  int puerto = 0;
  sockaddr_in local_address = make_ip_address(direccion_ip, puerto);
  Socket s(local_address);


  // Dirección del socket remoto
  string direccion_ip_remota = "0.0.0.0";
  int puerto_remoto = 0;
  sockaddr_in remote_address = make_ip_address(direccion_ip_remota, puerto_remoto);
  Socket s2(remote_address);

  //A continuación vamos a copiar el mensaje almacenado en nuestro string hacia la clase
  message_text.copy(s.message.text, sizeof(s.message.text) - 1, 0);
  s.send_to(s.message, remote_address);
  return 0;

}


Os paso también el cpp de la clase Socket que estoy creando, justo en la función send_to es donde se almacena el valor de result que da -1 y por consiguiente error...

#include "socket.hpp"

Socket::Socket(const sockaddr_in& address){

  /*Creación del socket || Devuelve un descriptor de archivo con el que
  identificar al socket en cuestión de futuras operaciones que se hagan
  sobre él

                        socket(domain, type, protocol)

  domain -> AF_INET | Porque estamos interesados en la tecnología TCP/IP

  type -> SOCK_DGRAM |Nuestro tipo de socket nos interesa que sea de tipo datagram

  protocol -> 0 | Protocolo específico que queremos que sea utilizado internamente
  por el socket para el envío de datos. En nuestro caso con la familia IP (AF_INET)
  con sockets tipo datagram (SOCK_DGRAM) sólo admite UDP como protocolo, por lo que
  este argumento debe ser 0 */

  fd = socket(AF_INET, SOCK_DGRAM, 0);
  check_socket_ini(fd);
  int result = bind(fd, reinterpret_cast<const sockaddr*>(&address), sizeof(address));
  check_socket_bind(result);

  /* Cuando un socket es creado a través de socket(), existe en un ambiente (adress family), pero
  no tiene una dirección asignada. Una dirección se asigna a un socket que acabamos de crear
  mediante la llamada al sistema bind()

                int bind(int sockfd, const sockaddr* addr, socklen_t addrlen)

  bind() no acepta una dirección IP y un número de puerto como parámetros. En su lugar recibe una
  estructura sockaddr genérica que puede dar cabida a cualquier tipo de dirección.
  Por ejemplo, para AF_INET se utiliza la estructura sockaddr_in declarada en <netinet/ip.h>.


  struct sockaddr_in {
      sa_family_t    sin_family; // dominio: AF_INET
      in_port_t      sin_port; // número de puerto en
              // orden de bytes de la red.
      struct in_addr sin_addr; // dirección de internet
  };

  // Dirección de internet
  struct in_addr {
      uint32_t       s_addr; // dirección en orden de bytes
  // de la red.
  };
*/

}

Socket::~Socket(){

}

int Socket::check_socket_ini(int fd){

  if (fd < 0){
    std::cerr << "No se pudo crear el socket: " << //std::cerr no tiene un buffer, generalmente se usa para errores
          std::strerror(errno) << '\n';
    return 3; // Error. Termina el programa siempre con un valor > 0 || (return 3 - El sistema no puede encontrar la ruta especificada)
  }
}

int Socket::check_socket_bind(int result){

  if (result < 0){
    std::cerr << "Falló bind: " << std::strerror(errno) << '\n';
    return 5; // Error. Termina el programa siempre con un valor > 0 || return 5 - Acceso denegado
  }
}

void Socket::send_to(const Message& message, const sockaddr_in& address){

  int result = sendto(fd, &message, sizeof(message), 0, reinterpret_cast<const sockaddr*>(&address), sizeof(address));
  check_message_send(result);
  cout << result << endl;

}

void Socket::receive_from(Message& message, sockaddr_in& address){

//  int result = recvfrom(fd, &message, sizeof(message), 0, reinterpret_cast<sockaddr*>(&remote_address), &src_len);

}

int Socket::check_message_send(int result){

  if (result < 0) {
    std::cerr << "Falló sendto: " << std::strerror(errno) << '\n';
    return 6;
  }
}


Gracias de antemano, es una conexión tipo UDP. Estoy tratando de hacer el cliente y el servidor en el mismo fichero, no sé si es lo más correcto o si es posible...


ivancea96

Si el sendto retorna SOCKET_ERROR (-1), utiliza la función WSAGetLastError Para ver qué error hubo.
Aquí ves qué significa cada valor devuelto por WSAGetLastError: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740148(v=vs.85).aspx