Servidor de sockets en c

Iniciado por xGisKaRDx, 10 Julio 2014, 23:04 PM

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

xGisKaRDx

Hola amigos estoy intentando de hacer un servidor de sockets en c bajo linux y bueno sinceramente no tengo mucha idea de c y me cuesta bastante entenderlo, ya no tengo capacidad para aprender un lenguaje de tan bajo nivel.
Bueno a lo que iba solo quiero aprender lo que implica de un servidor de sockets para poder hacer un servidor para un juego, bueno en realidad serán 2 servidores un para el juego y el otro para servir un crossdomain.xml

De momento he empezado a hacer pruebas con el servidor encargado de servir el xml la lógica consiste en lo siguiente, el cliente se conecta al servidor de xml al puerto 843 y le manda una cadena, el servidor comprueba dicha cadena y si la cadena coincide le contesta con un xml, una vez el cliente tiene el xml se desconecta automáticamente de ese servidor y se conecta al servidor del juego, el problema reside en que no me devuelve el xml.

Para probar el servidor lo que hago de momento es conectarme a través de telnet y una vez conectado le envió la cadena "<policy-file-request/>" y el servidor debería enviarme el xml, pero no me lo devuelve

en la consola de putty puedo ver mediante el comando put() como la cadena que yo le envió al servidor le llega de la siguiente manera.

<
policy-file-request/>

El primer carácter lo muestra en una línea y el resto de la cadena en la siguiente, no sé si esto puede llegar a afectar en algo.

A mí en cambio en la consola de telnet el servidor me devuelve la cadena que yo le envié de manera correcta <policy-file-request/> pero me tendría que devolver también el xml

En definitiva el siguiente if no se está cumpliendo   if(strcmp(buffer, "<policy-file-request/>")==0){



El código de ejemplo que estoy utilizando es este, agradezco cualquier corrección o ayuda.



#include<stdio.h>
#include<string.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write

int main(int argc , char *argv[])
{
    int socket_desc , new_socket , c;
    struct sockaddr_in server , client;
    char *message , buffer[2000];
int read_size;

     
    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }
     
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 843 );
     
    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        puts("bind failed");
        return 1;
    }
    puts("bind done");
     
    //Listen
    listen(socket_desc , 5);
     
    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);

while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) ){

           puts("Conexion establecida al servicio de crossdomain policy");
      //Miramos que nos dice el cliente
     //memset(buffer, '\0', sizeof( buffer ));
   memset(buffer, 0, 2000);
   // read_size = recv(new_socket , buffer , 20 , 0);

   //Receive a message from client
    while( (read_size = recv(new_socket , buffer , 2000 , 0)) > 0 ){
                   //Send the message back to client
     puts(buffer);
                     
  if(strcmp(buffer, "<policy-file-request/>")==0){//Si concuerda con la cadena "<policy-file-request/>" enviamos el cossdoamain al cliente
                        message = "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>";
                        write(new_socket , message , strlen(message));
              }
  write(new_socket , buffer , strlen(buffer));
  memset(buffer, 0, 2000);
                }
   
   if(read_size == 0){
             puts("Client disconnected");
             fflush(stdout);
           }else if(read_size == -1){
             perror("recv failed");
           }
    }//End While 
    if (new_socket<0){
        perror("accept failed");
        return 1;
    }
     
    return 0;
}

MeCraniDOS

Esto está mal

message = "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>";

Declaras un puntero a message pero no especificas tamaño, y por lo que he visto, message siempre tiene ese contenido, asi que prueba esto:

En la declaración de las variables:



int socket_desc , new_socket , c;
struct sockaddr_in server , client;
char buffer[2000], message[] = "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>";
int read_size;


Y en el if, tienes esto:

if(strcmp(buffer, "<policy-file-request/>")==0)
{
    //Si concuerda con la cadena "<policy-file-request/>" enviamos el cossdoamain al cliente
    message = "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>";
    write(new_socket , message , strlen(message));
}

                     
Cambialo por esto

if(strcmp(buffer, "<policy-file-request/>")==0)
{
    //Si concuerda con la cadena "<policy-file-request/>" enviamos el cossdoamain al cliente
    write(new_socket , message , strlen(message));
}


Si te sigue fallando lo miraré a ver cual puede ser el error

Saludos 


"La física es el sistema operativo del Universo"
     -- Steven R Garman

xGisKaRDx

#2
Hola MeCraniDOS, gracias por tu respuesta al final me ha funcionado con tus correcciones, gracias :)
Sinceramente vengo de lenguajes de alto nivel como js,php,as3,vb y c# y me cuesta mucho entender cosas como los punteros o por ejemplo me choca que no pueda comparar 2 cadenas tal cual en fin tiene mucha telita el c. supongo que al disponer de acceso a más bajo nivel se tiene más control pero para los cabeza duras como yo se nos hace un mundo.

Ya que estoy aprovecho para preguntar algunas cosillas, yo ahora mismo estoy programando en c con el notepad++ desde windows, cada vez que realizo algún cambio en el programa y quiero probarlo tengo que subirlo al ftp del vps(centos) después desde el putty lo compilo, mato el proceso del programa anterior desde el power panel y vuelvo a ejecutar el actualizado desde el putty para poder después probar el cambio realizado en el programa.

La pregunta es, hay alguna manera desde windows que yo pueda debuguear el servidor de sockets sin tener que hacer todos esos pasos cada vez que hago un cambio?
y para terminar, antes de seguir con el servidor de sockets en c me recomiendan algún otro lenguaje de más alto nivel para hacer el servidor de sockets pero que se ejecute desde linux como lo hace el c?
Bueno pues eso es todo, gracias y si sigo con el c seguramente iré viniendo más a menudo a visitarles jeje
Aquí dejo el código final de la duda anterior por si a alguien le sirve


#include<stdio.h>
#include<string.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write

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

int SOCKET_MASTER;
int SOCKET_CLIENT;
int sockAddrClientLen;
int read_size;

   struct sockaddr_in structServer;
struct sockaddr_in structClient;

char xml_message[] = "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>";
char error_message[] = "No se a enviado el xml porque no coincide el comando, la cadena recibida a sido:\n";
char buffer[2000];
     /*
* Creamos el SOCKET_MASTER
 */
   if ((SOCKET_MASTER = socket(AF_INET , SOCK_STREAM , 0)) == -1){
       printf("Could not create socket");
   }
     /*
* Cumplimentamos los valores de configuracion de la estructrua sockaddr_in
 */
   structServer.sin_family      = AF_INET;
   structServer.sin_addr.s_addr = INADDR_ANY;
   structServer.sin_port        = htons( 843 );
     /*
* Enlazamos el socket master a la ip y el puerto especificado en la estructura del server
 */
   if( bind(SOCKET_MASTER,(struct sockaddr *)&structServer , sizeof(structServer)) < 0){
       puts("Fallo en el enlace/Bind");
       return 1;
   }else{
       puts("Enlace realizado");
}
     /*
* Ponemos el socket a la escucha y con un maximo de 5 clientes en espera
 */  
   listen(SOCKET_MASTER , 5);
   puts("Esperando conexiones entrantes...");
  /*
* Ponemos el socket a la escucha y con un maximo de 5 clientes en espera
 */
   sockAddrClientLen = sizeof(struct sockaddr_in);
 /*
* Comprobamos mediante un bucle si se conecta algun cliente por el socket_master, si es asi aceptamos la conexion y creamos un nuevo socket para el cliente
 */
while( (SOCKET_CLIENT = accept(SOCKET_MASTER, (struct sockaddr *)&structClient, (socklen_t*)&sockAddrClientLen)) ){
         
  puts("Conexion establecida al servicio de crossdomain policy");
      //Inicializamos el buffer a 0
  memset(buffer, 0, 2000);
  //Comprovamos si el cliente conectado nos envia algun dato
 
  while( (read_size = recv(SOCKET_CLIENT , buffer , 2000 , 0)) > 0 ){
              //Mostramos en consola/putty el mensaje del cliente
  puts(buffer);
  //Comparamos si el mensaje enviado por el cliente coinciden los 20 primeros digitos con la siguiente cadena -> <policy-file-request/>
  if(strcmp(buffer, "<policy-file-request/>")==0){
                   //Si coincide le enviamos al cliente el xml
                   write(SOCKET_CLIENT , xml_message , strlen(xml_message));
       }else{
   //Si no coicide avisamos al cliente y le devolvemos tambien lo que nos envio el
write(SOCKET_CLIENT , error_message , strlen(error_message));
write(SOCKET_CLIENT , buffer , strlen(buffer));
}
//Reiniciamos a 0 el buffer
   memset(buffer, 0, 2000);
           }//End While read_size

  if(read_size == 0){
            puts("Cliente desconectado");
            fflush(stdout);//Forzamos a mostrase la cadena del buffer en consola
          }else if(read_size == -1){
            perror("Error en recv");
          }
   }//End While SOCKET_CLIENT

   if (SOCKET_CLIENT<0){
       perror("Error al Aceptar el nuevo Cliente/Socket");
       return 1;
   }
   
   return 0;
}





MeCraniDOS  cante victoria demasiado pronto, al ver que me devolvia el xml di por sentado que ya funcionava bien, pero el problema ahora es que mande lo que mande desde el telnet al servidor el servidor me devuelve el xml y solo me lo tiene que devolver si yo le mando la cadena <policy-file-request/>


PD: ya esta solucionado xd en la linea 70 estaba enviando nuevamente la variable xml_message y tenia que poner la variable error_message, ya esta corregido en el codigo.




Bueno pues sigue fallando... la que estoy liando qie si va que si no va.. en fin.

Ahora cuando envio una cadena desde telnet por ejemplo "hola"

en la consola muestra primero la primera lentra en una linea y el restro de la frase en la otra


por ejemplo:

h
ola

Sin envio "elhacker"

en consola me aparece

e
lhacker

supomngo que por eso cuando envio "<policy-file-request/>"
la sentencia if no se cumple y no me envia el xml

porque en vez de llegar al buffer la cadena "<policy-file-request/>" llega primero el "<" y luego el resto "policy-file-request/>"

es como si la linea del -> while( (read_size = recv(SOCKET_CLIENT , buffer , 2000 , 0)) > 0 ){

leiera el primer caracter del comando recibido y lo enviara y despues leiera el resto del comando


Si envio el comando desde telnet precedido por un espacio o alguna letra entonces funciona

por ejemplo:

x<policy-file-request/>

el servidor muestra en una linea la x y en la siguiente el resto

x
<policy-file-request/>

Entonces como se cumple la sentencia me devuelve el xml

Alguien sabe a que es debido ese comportamiento, porque el servidor corta la primera letra del resto de la cadena y lo muestra por separado?




Bueno espero que esta sea la ultima vez que digo que ya funciona bien y luego no..

En principio el problema venia por hacer las pruebas desde telnet, no me pregunteis porque, porque no tengo ni puñetera idea.

La cuestion es que he creado un cliente en flash me conectado y funciona a las mil maravillas

Saludos

vangodp

no se nada de socktes pero lo de
Citarno pueda comparar 2 cadenas tal cual en fin tiene mucha telita el c
se arregla guardando como C++ y entonces puedes utilizar todo el arsenal XD

string palabra = "hola";

i( palabra == "hola"){
//correcto
}

y puedes seguir usando c igual sin problemas >_<
C esta en C++  :¬¬

naderST

Cita de: MeCraniDOS en 11 Julio 2014, 00:20 AM
Esto está mal

message = "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>";

Declaras un puntero a message pero no especificas tamaño, y por lo que he visto, message siempre tiene ese contenido, asi que prueba esto:
...

En realidad, eso no está mal... la cadena "<?xml version=\"1.0\"?><!DOCTYPE cross-domainpolicy- SYSTEM \"http://www.adobe.com/xml/dtds/crossdomain.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>" es un literal y el apuntador message apunta a este. Al declarar una cadena en C entre comillas dobles automáticamente se agrega el caracter nulo (\0) al final, por lo tanto se pueden utilizar las funciones de la librería string tales como strlen y strcmp . Exactamente no se cual es el problema que tienes, pero sin duda alguna esa declaración no es parte del problema.

Por otra parte, dependiendo de lo que quieras hacer, puedes utlizar node.js o Python y te evitarás problemas con detalles de C

xGisKaRDx

Hola gracias por los comentarios, en realidad me estoy planteando, montarlo en java en vez de en c que por lo visto tambien puedo hacerlo correr en linux, ya que veo que en java practicamente todas estas cosas de bajo nivel estan axtraidas. no quiero hacerme la vida imposible con el servidor de sockets porque luego me quedara toda la programacion por parte del cliente/juego que es donde quiero invertir el tiempo.

Osea me gustaria un lenguaje parecido a algo que ya conociera de alto nivel como js, php, as3
(ya monte un servidor de sockets en php y no me convencio, tambien lo monte en adobe air pero no puedo instarlo en el vps porque ya no tiene soporte para linux, aunque podria instalarlo en uno windows pero el precio se dispara)

Asi que, que me recomiendan para crear un proceso de sockets para linux? java o c++?

naderST

Cita de: xGisKaRDx en 13 Julio 2014, 21:42 PM
Hola gracias por los comentarios, en realidad me estoy planteando, montarlo en java en vez de en c que por lo visto tambien puedo hacerlo correr en linux, ya que veo que en java practicamente todas estas cosas de bajo nivel estan axtraidas. no quiero hacerme la vida imposible con el servidor de sockets porque luego me quedara toda la programacion por parte del cliente/juego que es donde quiero invertir el tiempo.

Osea me gustaria un lenguaje parecido a algo que ya conociera de alto nivel como js, php, as3
(ya monte un servidor de sockets en php y no me convencio, tambien lo monte en adobe air pero no puedo instarlo en el vps porque ya no tiene soporte para linux, aunque podria instalarlo en uno windows pero el precio se dispara)

Asi que, que me recomiendan para crear un proceso de sockets para linux? java o c++?

Lo más parecido a lo que mencionas es node.js y si quieres más abstracción y tus opciones son Java y C++ te recomiendo que te vayas por Java. Sin embargo, node.js se programa utilizando javascript prácticamente.

xGisKaRDx

Gracias creo que optare por remirarme tanto c++ como java y luego decidiré, en cuanto a node.js la verdad es que me atrae el tema del control de los hilos mediante eventos pero sinceramente no me gusta javascript, es feo y malo de narices, en fin no me gusta para la web así que menos para el servidor, lástima que tengamos que tragarlo por fuerza.

además no veo un sistema de inicio claro en la instalación de node.js como por ejemplo c que tan solo tuve que poner en mi vps centos una línea para instalar el compilador gcc y a funcionar los programas con ./programa.out, no tuve que tocar nada más.

Espero que nadie se ofenda 

Gracias de nuevo y un salúdate.