Modelo ISO de comunicación entre sistemas. Simplificado en la época de TCP/IP.
Un poco de historia: ARPANET, OSI, CERN, ICANN, etc... (fuente IEEE)
iface eth0 inet static
address 192.168.1.10
network 192.168.1.0
netmask 255.255.255.0
broadcast 192.168.1.255
gateway 192.168.1.254
Internet Topology Map, January 2009 (UC Regent)
$ ip a
¡Ya puedo navegar por internet!
www.nachodigital.com.ar -> 66.228.47.221
$ ping www.wikipedia.org
PING dyna.wikimedia.org (208.80.154.224): 56 data bytes
64 bytes from 208.80.154.224: icmp_seq=0 ttl=52 time=175.908 ms
64 bytes from 208.80.154.224: icmp_seq=1 ttl=52 time=174.921 ms
El DNS nos ha dicho que la IP de
www.wikipedia.org es 208.80.154.224
Ya tenemos la dirección IP... ¿Que nos falta?
Direcciones IP:
Puertos:
Cada uno, espacios de puertos por protocolo.
www.nachodigital.com.ar:80
Siempre arriba de 1024
NetCat:
sudo apt install netcat
nc -n -vv -l -p 4161
nc 127.0.0.1 4161
echo "Hola Mundo" | nc 127.0.0.1 4161
cat test.txt | nc 127.0.0.1 4161
sudo apt-get install tcpdump
sudo tcpdump -i lo
sudo apt-get install wireshark
kdesu wireshark -i lo
Nota: Ambos programas hay que correrlos como root para poder capturar (por eso el uso de sudo).
Si misma red y problemas:
sudo iptables -F
iptables es un firewall que viene con linux.
Esto limpia las reglas que trae.
Para saber que hay configurado:
sudo iptables -L
unsigned long htonl (unsigned long hostlong)
Convierte un long del formato de la máquina al de la red.
unsigned short htons (unsigned short hostshort)
Convierte un short del formato de la máquina al de la red.
unsigned long ntohl (unsigned long netlong)
Convierte un long del formato de la red al de la máquina.
unsigned short ntohs (unsigned short netshort)
Convierte un short del formato de la red al de la máquina.
int socket(int domain, int type, int protocol);
Luego lo usamos mediante el file descriptor (ambos)
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
Existe un struct sockaddr, pero para un manejo
mas sencillo en TCP/IP se usa:
struct sockaddr_in {
short int sin_family; // familia de direcciones, AF_INET
unsigned short int sin_port; // Número de puerto
struct in_addr sin_addr; // Dirección de Internet
unsigned char sin_zero[8]; // Relleno para preservar el tamaño
// original de struct sockaddr
};
Dirección de Internet (una estructura por herencia histórica):
struct in_addr {
unsigned long s_addr; // Esto es un long de 32 bits, ó 4 bytes
};
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr,
socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
read() - Lectura de archivos o sockets:
ssize_t read(int fd, void *buf, size_t count);
write() - Escritura en archivos o sockets:
ssize_t write(int fd, const void *buf, size_t count);
Ambas funciones son bloqueantes y pensadas para archivos.
Se quedan esperando hasta que algo haya para leer o se pueda
enviar la data a enviar.
Estas funciones son especificas para manejo de sockets
y proveen información adicional (flags).
send() - Envio de datos por un socket:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
recv() - Recepción de datos desde un socket:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
Como la comunicación es inconexa no es necesario conectarse al socket, solo usarlo. Igual es como si hubiera un servidor/cliente. Siempre uno tiene que quedarse escuchando, el que recibe.
Estas funciones son el send/recv con manejo de sockets UDP
ya que permiten especificar el otro participante.
sendto() - Envio de datos por un socket UDP:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
recvfrom() - Recepción de datos desde un socket UDP:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
Archivos:
Archivos:
Archivos:
Archivos:
Parte no bloqueante de sockets_3client_nonblocking.c
printf("wait...");
do {
n = recv(sockfd,buffer,255,MSG_DONTWAIT);
printf(".");
} while (n == -1);
Trabajando en modo no bloqueante, retorna:
Mayormente no cambia. Tenemos los mismo pasos:
No en este ejemplo, pero se puede cambiar el server a una máquina de estados. De esa manera y como no bloqueante se pueden manejar multiples conexiones simultaneamente. Pero para poder manejar distintos sockets es mejor usar fork()
Compilar los ejemplos de código:
$ gcc -o client sockets_3client_nonblocking.c
$ gcc -o server sockets_3server_nonblocking.c
Fork nos permite crear un proceso "hijo", copia del "padre".
man 2 fork
#include <unistd.h>
pid_t fork(void);
El proceso hijo es un duplicado del padre, pero
tiene un PID distinto (valor retornado pid_t).
$ gcc -o ej1 ej_fork.c
man 2 wait
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
Si bien Unix originalmente copiaba toda la memoria del proceso padre, Linux desde el principio fue pensando para intel 386 que tiene "copy on write" lo que permite usar la misma memoria hasta que el programa cambie un dato.
Por esto una vez copiado, la dirección a mostrar es la misma. Pero existe otra razón adicional, Linux tiene un manejo de memoria virtual. Lo que nos muestra puede tener el mismo puntero, pero no es la misma dirección de memoria física (ref).
gcc -o ej2 ej_fork_kill.c
Para el segundo ejemplo utilizaremos los comandos:
gcc -o ej3 ej_fork_count.c
En este ejemplo vemos padre e hijo trabajando en paralelo.
Notas sobre el uso de fork y la memoria virtual.
Codigo:
$ gcc -o ej3-tcp-clt tcp-cliente.c
$ gcc -o ej3-tcp-svr tcp-servidor.c
$ ./ej3-tcp-svr
$ ./ej3-tcp-clt 127.0.0.1
$ ./ej3-tcp-clt 127.0.0.1
...
$ ps ax | grep ej3
$ gcc -o ej4-udp-clt udp-cliente.c
$ gcc -o ej4-udp-svr udp-servidor.c
$ ./ej4-udp-svr
$ ./ej4-udp-clt 127.0.0.1 Hola
$ ./ej4-udp-clt 127.0.0.1 Mundo
Codigo:
const int uno=1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&uno,
(socklen_t)(sizeof(uno)));
$ gcc -o al08_keyboard_client al08_keyboard_client.c -lallegro -lallegro_main -lallegro_image -lallegro_primitives
$ gcc -o al08_keyboard_server al08_keyboard_server.c -lallegro -lallegro_main -lallegro_image -lallegro_primitives
$ ./al08_keyboard_server
$ ./al08_keyboard_client 127.0.0.1