Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Sdl_net Y Servidor-cliente En Local

Iniciado por LC0, 24 de Septiembre de 2005, 04:52:13 PM

« anterior - próximo »

LC0

 Hola.

Tendré que reescribir esto desde cero, ya que antes se me cerró el navegador misteriosamente, pero bueno, ahí va  (nooo) :

Estoy metido en un pequeño proyecto de una biblioteca de red para juegos, básicamente en tiempo real (vamos, UDP), implementándola a partir de la biblioteca SDL_net.
El caso es que antes estaba haciéndola con los sockets BSD, pero decidí cambiar ya que portar estos a Windows no es tan sencillo como en un principio me parecía.

A la hora de hacer la prueba fatal (ejecutar el servidor, luego el cliente y, tras mandarle este último un mensaje, el servidor imprime "Recibido, líder rojo"). Esta prueba la he reducido a que el servidor espere que un jugador se conecte, y que, cuando ocurra, este envie una petición para unirse al juego y el servidor se ponga contento al descubrir que no está solo en el universo, y aceptarle en la partida.

Con los sockets BSD no había ningún problema al hacer esto (ya digo, tanto cliente como servidor bajo el mismo ordenador), pero con SDL_net, el cliente se aborta abruptamente con un flamante "SDL Parachute Deployed". Si hago que el puerto del socket del servidor sea diferente al del cliente, elimino este fallo; pero claro, obviamente, el mensaje no llega a recibirse.

Mi pregunta es: ¿Estoy haciendo algo mal o realmente tendré que comprarme un portátil, instalarme una máquina virtual como Quemu, o depender de algún amigo para realizar las pruebas, para ejecutar al cliente y al servidor en diferentes máquinas?

Os pongo los trozos de código relevantes.

Este de aquí es el servidor:

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

 GDServerr Serverr;
 Serverr.startServer();
 while(1)
Server.adminIncomingConnections();

 return 0;
}


El miembro adminIncomingConnections:

void GDServer::adminIncomingConnections()
{
UDPpacket p;
if(SDLNet_UDP_Recv(SocketConnections,&p))
{
 std::cout << "Mensaje de conexión recibido: " << (int)p.data[0] <<  std::endl;
 if(CurrentClients<MaxClients)
 {
  CurrentClients++;
  Sockets.push_back(SDLNet_UDP_Open(p.address.port));
  SDLNet_UDP_AddSocket(SocketSet,Sockets[Sockets.size()-1]);
 }
}
}


El cliente:

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

 GDClient client;
 if(!client.connect("127.0.0.1"))
cout << "Fallo en la comunicación con el servidor" << endl;
 
 return 0;
}


Y el método connect:


//Connection to a server
bool GDClient::connect(const char* dir,int timeout,int port) /*throw(GDError)*/
{
AdminSocket=SDLNet_UDP_Open((Uint16)port);

IPaddress Ip;
SDLNet_ResolveHost(&Ip,const_cast<char*>(dir),(Uint16)port);

int channel=SDLNet_UDP_Bind(AdminSocket,-1,&Ip);
if(channel==-1)
 std::cerr <<"GDClient::Connect(): No se pudo crear canal. "<< SDLNet_GetError() << std::endl;
UDPpacket* packet=SDLNet_AllocPacket(sizeof(Uint8));
packet->data[0] = GD_NETMSG_CONNECT;
if(!SDLNet_UDP_Send(AdminSocket,channel,packet))
 std::cerr <<"GDClient::Connect() : No se pudo enviar mensaje. "<< SDLNet_GetError() << std::endl;


Uint32 t1=SDL_GetTicks();
while(SDL_GetTicks() - t1 <= (Uint32)timeout)
{
 if(SDLNet_UDP_Recv(AdminSocket,packet))
 {
  SDLNet_FreePacket(packet);
  return true;
 }
}

SDLNet_FreePacket(packet);
return false;

}


Muchísimas gracias de antemano :).

vicho

 yo estoy usando SDL_Net hace ya bastante tiempo para el juego que estoy haciendo (mas de 1 año) y la verdad es que antes tenia 2 maquinas una era el servidor y la otra el cliente. pero hace ya un par de meses hice que el juego hiciese las 2 cosas en un mismo programa. en fin..

yo uso el manejador de socket_sets, te aconsejaria que le hechases una mirada, ya que es bastante completo
y no e tenido ningun problema, por lo tanto comprar un computador nuevo, deberia ser algo descartable :P


LC0

 Sí sí, los conjuntos de sockets los tendré que usar tarde o temprano :P. Digamos que los sockets estos aislados son, simplemente, para admitir y desadmitir peticiones de entrada en el juego.
Gracias por la respuesta, cogeré a alguien para que me haga de cobaya humano :D.

LC0

 Pues un amigo y yo acabamos de probar el cliente y el servidor (en diferentes ordenadores, se entiende :D) y no se produce comunicación: El cliente se sale con un flamante GDClient::Connect() : No se pudo enviar mensaje. y el servidor, por ende, no rcibe nada.
Y no hago más que mirar y mirar el código y no encuentro nada malo a mis ojos. ¿En que me estoy equivocando?
Otra vez gracias de antemano.

vicho

 pero tas usando udp no??

bueno la cosa es que en udp no existe coneccion realmente. :huh:  

LC0

 Sí sí, UDP.
La idea es que se "simule" la conexión esa que tú dices... El código de arriba es una especie de miniprotocolo para acceder a una partida en red: El cliente (jugador) envía un mensaje al servidor vía un puerto especial de que quiere unirse la partida, y se queda esperando un cierto tiempo (el timeout, vamos) hasta que, o el servidor le contesta que puede meterse o que no, o que no llegue el mensaje de respuesta y el cliente se canse.
Al final lo que he hecho es usar un vector de paquetes con AllocPacketV, y parece que así sí que va. Tal vez sea un fallo de la implementación de SDLNet_UDP_Send: Lo habrán hecho, a todos los efectos, no bloqueante, sin importar el timeout que le pases por parámetro. Sería cuestión de mirar el código :D.
Gracias mil, vicho. Un saludo.

ethernet

 Nunca he usado SDL_net, pero mirando los ejemplos he visto que para enviar un packet primero ponen los datos en data y a continuación setean un parámetro llamado len al tamaño de lo enviado.


UDPpacket* packet=SDLNet_AllocPacket(sizeof(Uint8));
packet->data[0] = GD_NETMSG_CONNECT;
packet->len = 1;


No sé si será eso.

Otra cosa que puedes hacer usar SDLNet_GetError() (que retorna una cadena) para saber qué pasa.

Suerte

LC0

 Sí, yo también leí lo del len, pero lo probé y no funcionó. Eso sí, no está de más y debería haberlo dejado puesto , y en futuras ocasiones, para el envío de datos "ingame", sí que van a hacer mucha falta.
Y lo del SDLNet_GetError, está puesto :).

ethernet

Cita de: "LC0"Sí, yo también leí lo del len, pero lo probé y no funcionó. Eso sí, no está de más y debería haberlo dejado puesto , y en futuras ocasiones, para el envío de datos "ingame", sí que van a hacer mucha falta.
Y lo del SDLNet_GetError, está puesto :).
Aja, pero en tu post de antes no has puesto lo que saca get_error, solo sacas la cadena que has puesto tú. No saca ningún error ?

Otra cosa, no tendreis alguno firewall o similar :? xD

LC0

 
Citar
Aja, pero en tu post de antes no has puesto lo que saca get_error, solo sacas la cadena que has puesto tú. No saca ningún error ?
Que va, lo que sale es lo que has visto.

Citar
Otra cosa, no tendreis alguno firewall o similar :? xD
Jajaja, que va, nunca hemos hecho nada para cabrear a ningún juanker y, como usamos Linux, pues... ¿pa' que? xDD.

Por cierto, fijaos que curioso:Si pillo un vector de sockets de tamaño 10, todo funciona bien y sin problemas, aún cuando solamente envío el primero (SDLNet_UDP_SendV(AdminSocket,packet,1)). Pero si reservo este vector tan solo de tamaño 1 (1 paquete, se entiende) el servidor no recibe ningún mensaje  :huh: . Me está sorprendiendo bastante esta biblioteca, la verdad :D.

TheAzazel

 Bueno, yo me lleve un par de sorpresas con ellas.... pero al final consegui que todo funcionara bien... aunque esta todo basado en TCP.
Sobre UDP trabajare algo en las proximas semanas... asi que no te puedo decir mas....

Hay un framework de trabajo sobre SDL_net que funciona bastante bien(de hecho, fue lo que me inspiro a mi a intentar hacer algo parecido),
busca por aqui a ver si te sirve:

Net2 - SDL_net

suerte

LC0

 Pues muchas gracias, voy a echarle un vistazo :).
Ahora que todo parecía empezar a ir bien, he ampliado el pequeño ejemplo, y han vuelto a salir más fallos a primera vista inverosímiles. A ver si encuentro respuesta en este Net2, y si no, posteo aquí la duda.
Gracias de nuevo :).

LC0

 Uhmmm... no me gusta la idea que ofrece el Net2 de abstraer el concepto de socket y hacer que la información se reciba a través de "puertos". Al menos no para construir una capa de abstracción de la SDL_net :D, porque para otro uso más "directo" (vamos, videojuegos) es perfecto.

Una cosa que acaba de venirme a la mente y que no he posteado antes por aquí: Para esta biblioteca intento que el usuario final que la use no tenga que hacer ninguna llamada de inicialización (algo como GDNet.init() ), sino que esto sea automático y totalmente transparente. El código de la inicialización, a grosso modo, es:

//Clase de inicialización (en fichero de cabecera)
class GDInitClass
{
 GDInitClass();
 ~GDInitClass();
 static GDInitClass GDInit;
};

//En fichero .cpp
GDInitClass GDInitClass::GDInit;

//Constructor
GDInitClass::GDInitClass()
{
   SDL_Init(flags);
   SDLNet_Init();
}

//Destructor
GDInitClass::~GDInitClass()
{
   SDL_Quit();
   SDLNet_Quit();
}


En otras bibliotecas, como Allegro, cosas como esta podían dar lugar a efectos extraños: Allegro es una biblioteca que hace que las clases que hagas  deban tener un destructor "manual" que el usuario necesitará invocarlo para liberar los recursos de mapas de bits, sonidos, etc...
En SDL y SDL_Net, no parece que pase lo mismo, pero sí que ocurren cosas raras, como la que pregunté desde un principio en este hilo. Y, aparte, lo de que envíe los paquetes cuando pongo el tamaño al vector de paquetes como le da la gana.

Mi pregunta es: ¿Puede traer problemas de inicialización este método? ¿Puede ser una razón por la que haga lo que hace?
Gracias otra vez :D.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.