domingo, 23 de septiembre de 2012

Curso de sockets. Capitulo 2. Como programar un webserver

Capítulo perteneciente al curso de programación C/C++  LordPakus

Hola a todos,

El capítulo de hoy se centrará en programar un servidor de web html.

Un servidor web no es más un programa que usa los sockets para dar información que pueden representar los navegadores ( html )

Si nosotros montamos un servidor como el del capitulo anterior pero que está vez envie html al cliente ya tendremos un servidor web bien sencillo.

El código es el siguiente:


#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "Ws2_32.lib")
#define PUERTO 8080

WSADATA wsa;

int error()
{
    std::cout << "Error #" << GetLastError() << std::endl;
    WSACleanup();

    getchar();

    return 0;
}

int InitServer(sockaddr_in *local, SOCKET * servidor, int puerto)
{
local->sin_port = htons(puerto); // Puerto a la escucha.
local->sin_family = AF_INET; // Debe ser AF_INET.
local->sin_addr.S_un.S_addr = INADDR_ANY; // Usar cualquier dirección.

*servidor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   // Protocolo TCP
   
if(*servidor == INVALID_SOCKET)
return error();

if(bind(*servidor, (sockaddr*)local, sizeof(sockaddr)) == SOCKET_ERROR)
return error();

if(listen(*servidor, 1) == SOCKET_ERROR)     // Colocamos el servidor a la escucha.
return error();

std::cout << "Servidor a la escucha por el puerto " << puerto << ", esperando conexión." << std::endl;

return 0;
}

void WaitConnection(SOCKET *servidor, SOCKET * nueva_conexion )
{
do
{
*nueva_conexion = accept(*servidor, NULL, NULL); // Esperamos una conexión entrante y la aceptamos.
} while(*nueva_conexion == SOCKET_ERROR);
}

void SendMessage(SOCKET conexion,char *str)
{
send(conexion,str,strlen(str),0);
}

int WaitMessage(SOCKET conexion, char *bufout)
{
int bytes_recv;
char buffer[512];

memset(buffer, 0, sizeof(buffer)); // Limpiamos el buffer temporal
memset(bufout, 0, sizeof(buffer)); // Limpiamos el buffer de salida.

do
{
bytes_recv = recv(conexion, buffer, sizeof(buffer), 0);   // Esperamos para recibir datos...
} while(bytes_recv == 0 && bytes_recv != SOCKET_ERROR);

//Copiamos el buffer temporal en el de salida
memcpy(bufout,buffer,bytes_recv);

return bytes_recv;

}

int Server(void)
{
int res;
SOCKET servidor, nueva_conexion;
sockaddr_in local;
char buffer[512];
int bytes;

//Iniciamos el servidor
res = InitServer(&local,&servidor, PUERTO);

if ( res )
return res;

while(1)
{
//Esperamos que se nos conecte un cliente
WaitConnection(&servidor,&nueva_conexion);

std::cout << "Conecction received" << std::endl;

bytes = WaitMessage(nueva_conexion,buffer);

if(bytes > 0)
std::cout << "Buffer: " << buffer << " - Bytes recibidos: " << bytes << std::endl;

SendMessage(nueva_conexion,"<HTML><HEAD><TITLE>Un Titulo para el Browser de turno </TITLE></HEAD><BODY><H3>Pongamos un subtítulo<H3></BODY></HTML>");

closesocket(nueva_conexion);                                    // Lo desconectamos!
}

return 0;
}

int main()
{
char opcion;
int res;

if(WSAStartup(MAKEWORD(2,2), &wsa))
        return error();

std::cout << "Iniciando LordPakus WebServer" << std::endl;

res = Server();

if(res)
return res;

    WSACleanup();
system("PAUSE");
return 0;
}

Espero que os haya gustado. Para probarlo solo debéis arrancar vuestro navegador y en la ruta ponerle 127.0.0.1:8080. Ya vereis los resultados.

Nos vemos

jueves, 13 de septiembre de 2012

Curso de sockets. Capitulo 1

Capítulo perteneciente al curso de programación C/C++  LordPakus

Hola a todos,

Por petición popular ( y tal y como prometí) os adjunto un tutorial del uso de sockets en C sobre windows.

Los sockets no son más que la herramienta que nos da el sistema operativo para conectarnos a una red desde nuestro programa. Normalmente son dependientes de la API del SO, así que me restringo solamente a sistemas windows. Si algún valiente quiere hacer la versión para Linux, adelante!

Casi todas las estructuras de red actuales se basan en un configuración cliente-servidor. Es decir, tenemos un ordenador que se limita a escuchar por un puerto y otro ordenador que "ataca" a ese servidor en ese puerto. A través de esa información se realiza la comunicación.

Al contrario que en otros lenguajes, el tema de red en C no es ni fácil ni intuitivo (algo malo tenia que tener :D ), así que me limitaré a copiaros el código para que podáis hacer vuestras pruebas. cualquier duda que tengáis hacedmela llegar.

En breves dias encapsularé el código en C++ para que sea más legible.

Espero que os guste, nos vemos:

main.c



#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "Ws2_32.lib")
#define PUERTO 8080

WSADATA wsa;

int error()
{
    std::cout << "Error #" << GetLastError() << std::endl;
    WSACleanup();

    getchar();

    return 0;
}

int InitServer(sockaddr_in *local, SOCKET * servidor, int puerto)
{
local->sin_port = htons(puerto); // Puerto a la escucha.
local->sin_family = AF_INET; // Debe ser AF_INET.
local->sin_addr.S_un.S_addr = INADDR_ANY; // Usar cualquier dirección.

*servidor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   // Protocolo TCP
   
if(*servidor == INVALID_SOCKET)
return error();

if(bind(*servidor, (sockaddr*)local, sizeof(sockaddr)) == SOCKET_ERROR)
return error();

if(listen(*servidor, 1) == SOCKET_ERROR)     // Colocamos el servidor a la escucha.
return error();

std::cout << "Servidor a la escucha por el puerto " << puerto << ", esperando conexión." << std::endl;

return 0;
}

void WaitConnection(SOCKET *servidor, SOCKET * nueva_conexion )
{
do
{
*nueva_conexion = accept(*servidor, NULL, NULL); // Esperamos una conexión entrante y la aceptamos.
} while(*nueva_conexion == SOCKET_ERROR);
}

void SendMessage(SOCKET conexion,char *str)
{
send(conexion,str,strlen(str),0);
}

int WaitMessage(SOCKET conexion, char *bufout)
{
int bytes_recv;
char buffer[256];

memset(buffer, 0, sizeof(buffer)); // Limpiamos el buffer temporal
memset(bufout, 0, sizeof(buffer)); // Limpiamos el buffer de salida.

do
{
bytes_recv = recv(conexion, buffer, sizeof(buffer), 0);   // Esperamos para recibir datos...
} while(bytes_recv == 0 && bytes_recv != SOCKET_ERROR);

//Copiamos el buffer temporal en el de salida
memcpy(bufout,buffer,bytes_recv);

return bytes_recv;

}

int Server(void)
{
int res;
SOCKET servidor, nueva_conexion;
sockaddr_in local;
char buffer[256];
int bytes;

//Iniciamos el servidor
res = InitServer(&local,&servidor, PUERTO);

if ( res )
return res;

//Esperamos que se nos conecte un cliente
WaitConnection(&servidor,&nueva_conexion);

SendMessage(nueva_conexion,"Servidor C++!");

bytes = WaitMessage(nueva_conexion,buffer);

if(bytes > 0)
std::cout << "Buffer: " << buffer << " - Bytes recibidos: " << bytes << std::endl;

closesocket(nueva_conexion);                                    // Lo desconectamos!

return 0;
}

int InitClient(sockaddr_in *conexion,SOCKET * cliente, char *ip, int puerto )
{
conexion->sin_family = AF_INET;
conexion->sin_port = htons(PUERTO);                                    // Puerto donde nos conectaremos

conexion->sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

//Todo: Implementar tb por nombre de host
// conexion->.sin_addr = *((in_addr*)gethostbyname("localhost")->h_addr);  // Host a donde nos conectaremos

*cliente = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);        // Protocolo TCP

if(*cliente == INVALID_SOCKET)
return error();

if(connect(*cliente, (sockaddr*)conexion, sizeof(sockaddr)))      // Conectamos con el servidor
return error();

return 0;
}

int Client(void)
{
sockaddr_in conexion;
SOCKET cliente;
char buffer[256];
int bytes;
int res;

res = InitClient(&conexion,&cliente,"127.0.0.1",PUERTO);

if(res)
return res;
 
SendMessage(cliente,"Hola, soy un cliente en C++!");

bytes = WaitMessage(cliente,buffer);

if(bytes > 0)
std::cout << "Buffer: " << buffer << " - Bytes recibidos: " << bytes << std::endl;

closesocket(cliente);                                                       // Finalmente desconectamos...

return 0;
}

int main()
{
char opcion;
int res;

if(WSAStartup(MAKEWORD(2,2), &wsa))
        return error();

do
{
std::cout << "1-Servidor o 2-Cliente?" << std::endl;
opcion = getchar();
}
while( (opcion != '1') && (opcion != '2'));

if(opcion == '1')
{
std::cout << "Iniciando servidor" << std::endl;
res = Server();
  }
else
{
std::cout << "Iniciando cliente" << std::endl;
res = Client();
}

if(res)
return res;

    WSACleanup();
system("PAUSE");
return 0;
}



Entradas populares