You are on page 1of 8

Cliente y Servidor TCP

Client Server
socket socket

bind

listen

Establecimiento de accept
conexión
connect
(SYN)

write read

read write
Petición de cierre
close de
read
conexión
(FIN)
close

Redes de Área Local 2007 24

connect()
• Utilizada por el cliente para establecer una conexión
con un servidor.
int connect(int sockfd,
const struct sockaddr *serv_addr,
socklen_t addrlen);

– sockfd: Descriptor de socket


– serv_addr: Dirección del socket del servidor (dirección IP y
puerto) al que deseamos conectarnos. Será necesario realizar
cast de (sockaddr_in *) a (sockaddr *).
– addrlen: tamaño de la dirección de socket
– El valor de retorno indica si la conexión se ha establecido
correctamente. Es necesario comprobar este valor:
• 0: la conexión se ha establecido
• -1: la conexión ha fallado

Redes de Área Local 2007 25

1
listen()
• Se utiliza para definir el tamaño de la cola para almacenar el
número de conexiones entrantes pendientes de ser aceptadas.

int listen(int sockfd, int backlog);

– sockfd: Descriptor de socket


– backlog: número de conexiones entrantes pendientes de ser
aceptadas.
– El valor de retorno indica si ha habido algún error. Es necesario
comprobar este valor:
• 0: éxito
• -1: error

Redes de Área Local 2007 26

accept()
• Utilizada por el servidor para aceptar conexiones de
clientes. Por defecto es una llamada bloqueante.
int accept(int sockfd,
struct sockaddr *client_addr, servidor
socklen_t *addrlen);

– sockfd: Descriptor de socket


– client_addr: Cuando la llamada retorne tendrá
almacenada la dirección del socket del cliente
(dirección IP y puerto) que se ha conectado. Será
necesario reservar memoria.
– addrlen: parámetro de entrada/salida, al realizar la Socket Socket
llamada contiene el tamaño de la estructura pasivo conectado
client_addr, al retornar contiene el tamaño de la con un
estructura que ha sido devuelta. cliente
– El valor de retorno indica el descriptor de socket
conectado con dicho cliente y es el que usaremos para
realizar las operaciones de lectura/escritura con ese
cliente. Es necesario comprobar este valor, si es -1 ha
habido un error.

Redes de Área Local 2007 27

2
read()
• Lee los bytes de un descriptor. Por defecto es una llamada
bloqueante, si no hay bytes se quedará esperando.

int read(int sockfd, void *buf, size_t nbytes);

– sockfd: Descriptor de socket


– buf: Buffer donde se almacenarán los bytes leidos. Será necesario
reservar memoria.
– nbytes: número de bytes que se solicita leer.
– El valor de retorno indica el número de bytes leidos, que no tiene por
qué coincidir con nbytes. Si el valor devuelto es -1 ha ocurrido un
error.

Redes de Área Local 2007 28

write()
• Escribe los bytes en un descriptor. Puede ser una llamada
bloqueante, si el buffer de transmisión de TCP está lleno.

int write(int sockfd, const void *buf, size_t nbytes);

– sockfd: Descriptor de socket


– buf: Buffer que contiene los datos que se van a enviar.
– nbytes: número de bytes que se desea enviar.
– El valor de retorno indica el número de bytes escritos, comprobar
este valor. Si el valor devuelto es -1 ha ocurrido un error.

Redes de Área Local 2007 29

3
#define PUERTO_TCP 11000 Servidor TCP (I)
#define UNIXEPOCH 2208988800UL /* UNIX epoch, in UCT secs */

int main() {
int s, cs,leidos, escritos;
struct sockaddr_in srv_addr, client_addr;
socklen_t client_addr_len;
char buff[1];
time_t now;

if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) {


fprintf(stderr, "error en socket %s\n", strerror(errno));
exit(1);
}

srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(PUERTO_TCP);
srv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr *) &srv_addr, sizeof(srv_addr)<0) {
fprintf(stderr, "error en bind %s\n", strerror(errno));
exit(1);
}

if (listen(s, 5) <0) {
fprintf(stderr, "error en listen %s\n", strerror(errno));
exit(1);
}

Redes de Área Local 2007 30

while (1) { Servidor TCP (II)


memset(&client_addr, 0, sizeof(client_addr));
client_addr_len = sizeof(client_addr);

cs = accept(s, (struct sockaddr *)&client_addr, &client_addr_len);


if (cs <0) {
fprintf(stderr, "error en accept %s\n", strerror(errno));
exit(1);
}

leidos = read(cs, buff, sizeof(buff));


if (leidos < 0) {
fprintf(stderr, "error en read %s\n", strerror(errno));
exit(1);
}

time(&now);
now = htonl((unsigned long)(now + UNIXEPOCH));

escritos = write(cs, (char *)&now, sizeof(now));


if (escritos <0 ) {
fprintf(stderr, "error en write %s\n", strerror(errno));
exit(1);
}

close(cs);
} /* while */
} /* main */
Redes de Área Local 2007 31

4
Cliente TCP (I)
#define PUERTO_TCP 11000
#define UNIXEPOCH 2208988800UL /* UNIX epoch, in UCT secs */
#define MSG "Dime la hora"

int main() {

int s, escritos, leidos;


struct sockaddr_in srv_addr;
time_t now;

if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) {


fprintf(stderr, "error en socket %s\n", strerror(errno));
exit(1);
}

srv_addr.sin_family=AF_INET;
srv_addr.sin_port = htons(PUERTO_TCP);
srv_addr.sin_addr.s_addr = inet_addr(“10.0.0.1”);

if (connect(s, (struct sockaddr * ) &srv_addr, sizeof(srv_addr) < 0) {


fprintf(stderr, "error en connect %s\n", strerror(errno));
exit(1);
}

Redes de Área Local 2007 32

Cliente TCP (II)


escritos = write(s, MSG, strlen(MSG));

if (escritos < 0) {
fprintf(stderr, "error en sendto %s\n", strerror(errno));
exit(1);
}

leidos = read(s, (char *)&now, sizeof(now));

if (leidos < 0) {
fprintf(stderr, "error en sendto %s\n", strerror(errno));
exit(1);
}

now = ntohl((unsigned long)now);


now -= UNIXEPOCH;

printf("Hora: %s\n", ctime(&now));

close(s);
} /* main */

Redes de Área Local 2007 33

5
Netstat
• Netstat:
– Muestra las conexiones de red, tablas de encaminamiento,
estadísticas de interfaces de una máquina.

[eva@gsyc051:~/ral/ejemplos]$ netstat -ant


Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp 0 0 *.11000 *.* LISTEN
tcp 0 0 127.0.0.1.1033 127.0.0.1.963 ESTABLISHED
tcp 0 0 127.0.0.1.963 127.0.0.1.1033 ESTABLISHED
tcp 0 0 *.3689 *.* LISTEN
tcp 0 0 127.0.0.1.5679 *.* LISTEN

Redes de Área Local 2007 34

Servidor TCP iterativo vs.


concurrente
• Iterativo
– Nuevos clientes que deseen operar con servidor
el servidor deben esperar a que el
servidor termine de atender al cliente
actual. proceso proceso proceso
hijo hijo hijo

• Concurrente
– Permite que un servidor esté atendiendo

a varios clientes simultáneamente. Socket Socket Socket Socket
– El proceso servidor (proceso padre) crea pasivo conectado conectado conectado
un proceso hijo por cada petición de con un con un con un
cliente cliente cliente
conexión desde un cliente. Cada proceso
hijo atenderá las peticiones de su
cliente.

Redes de Área Local 2007 35

6
Servidor concurrente TCP (I)
#define PUERTO_TCP 11000
#define UNIXEPOCH 2208988800UL /* UNIX epoch, in UCT secs */

int main() {
int s, cs,leidos, escritos;
struct sockaddr_in srv_addr, client_addr;
socklen_t client_addr_len;

if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) {


fprintf(stderr, "error en socket %s\n", strerror(errno));
exit(1);
}

srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(PUERTO_TCP);
srv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr *) &srv_addr, sizeof(srv_addr)<0) {
fprintf(stderr, "error en bind %s\n", strerror(errno));
exit(1);
}

if (listen(s, 5) <0) {
fprintf(stderr, "error en listen %s\n", strerror(errno));
exit(1);
}

Redes de Área Local 2007 36

Servidor concurrente
TCP (II)
signal (SIGCHLD, termina_hijo);

while (1) {
memset(&client_addr, 0, sizeof(client_addr));
client_addr_len = sizeof(client_addr);

cs = accept(s, (struct sockaddr *)&client_addr, &client_addr_len);


if (cs <0) {
if (errno == EINTR)
continue;
fprintf(stderr, "error en accept %s\n", strerror(errno));
exit(1);
}

switch (fork()) {
case 0: /* proceso hijo */
close(s);
atiende_cliente(cs);
exit(0);
case 1: /* proceso padre */
close(cs);
break;
case -1:
fprintf(stderr, “error en fork %s\n”, strerror(errno));
exit(1);
}
} /* while */
} /* main */
Redes de Área Local 2007 37

7
Servidor concurrente TCP (III)
void atiende_cliente(int cs) {
int leidos, escritos;
char buff[1];
time_t now;

leidos = read(cs, buff, sizeof(buff));


if (leidos < 0) {
fprintf(stderr, "error en read %s\n", strerror(errno));
exit(1);
}

time(&now);
now = htonl((unsigned long)(now + UNIXEPOCH));

escritos = write(cs, (char *)&now, sizeof(now));


if (escritos <0 ) {
fprintf(stderr, "error en write %s\n", strerror(errno));
exit(1);
}

close(cs);

Redes de Área Local 2007 38

Servidor concurrente TCP (IV)


void termina_hijo(int sig) {
int estado;
while (wait4(-1, &estado, WNOHAG, (struct rusage *)0) >=0)
; /* vacío */
}

Redes de Área Local 2007 39

You might also like