jueves, 13 de septiembre de 2012

[Tutoriales online de Programación : Videojuegos, Game Engines y C/C++] Curso de sockets. Capitulo 1

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;
}





--
Publicado por Pako para Tutoriales online de Programación : Videojuegos, Game Engines y C/C++ el 9/13/2012 09:59:00 a.m.

No hay comentarios:

Publicar un comentario

Sigue todas las entradas por email