Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
A
ARS
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
danredo
ARS
Commits
0885e02c
Commit
0885e02c
authored
9 months ago
by
danredo
Browse files
Options
Downloads
Patches
Plain Diff
Upload New File
parent
116704d0
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
P6/daytime-tcp-server-L110.c
+170
-0
170 additions, 0 deletions
P6/daytime-tcp-server-L110.c
with
170 additions
and
0 deletions
P6/daytime-tcp-server-L110.c
0 → 100644
+
170
−
0
View file @
0885e02c
/**
* Practica Tema 6: DAYTIME TCP
*
* Redondo Calleja, Daniel
* Jimenez Prieto, Roberto
*/
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<unistd.h>
#include
<arpa/inet.h>
#include
<netdb.h>
// Para getservbyname()
#include
<signal.h>
// Para manejar señales
#include
<sys/socket.h>
// Para sockets
#include
<netinet/in.h>
// Para estructuras de sockets
#include
<errno.h>
#include
<sys/wait.h>
// Para waitpid()
#include
<stdbool.h>
// Para boolean
#define BUFF_SIZE 256
#define DEFAULT_SERVICE "daytime"
int
server_sockfd
;
// Socket principal del servidor
// Funcion para obtener la hora actual utilizando el comando "date"
void
get_date
(
char
*
buffer
,
size_t
longitud
)
{
FILE
*
file
;
system
(
"date > /tmp/date.txt"
);
// Ejecuta date y guarda la salida en un temporal date.txt
file
=
fopen
(
"/tmp/date.txt"
,
"r"
);
// Verificamos que se ha creado date.txt
if
(
file
==
NULL
||
fgets
(
buffer
,
longitud
,
file
)
==
NULL
)
{
perror
(
"Error al obtener la fecha con system() o fopen()"
);
exit
(
EXIT_FAILURE
);
}
fclose
(
file
);
}
// Manejador de señal para cerrar los sockets al recibir Ctrl+C (SIGINT)
void
signal_handler
(
int
signal
)
{
if
(
signal
==
SIGINT
)
{
printf
(
"
\n
Servidor TCP cerrando conexiones...
\n
"
);
close
(
server_sockfd
);
// Cerrar el socket principal del servidor
exit
(
EXIT_SUCCESS
);
}
}
// Funcion para manejar las conexiones de los clientes en procesos hijos
void
manejar_cliente
(
int
client_sockfd
)
{
char
buffer
[
BUFF_SIZE
],
date_buffer
[
BUFF_SIZE
];
char
hostname
[
BUFF_SIZE
];
// Obtenemos el nombre del host
if
(
gethostname
(
hostname
,
sizeof
(
hostname
))
<
0
)
{
perror
(
"Error al obtener el nombre del servidor"
);
close
(
client_sockfd
);
exit
(
EXIT_FAILURE
);
}
// Obtenenemos la fecha y hora actual
get_date
(
date_buffer
,
BUFF_SIZE
);
// Prepararamos la respuesta en formato "nombre: fecha"
snprintf
(
buffer
,
BUFF_SIZE
,
"%s: %s"
,
hostname
,
date_buffer
);
// Enviamos la respuesta al cliente
if
(
send
(
client_sockfd
,
buffer
,
strlen
(
buffer
),
0
)
<
0
)
{
perror
(
"Error al enviar la respuesta al cliente"
);
}
// Cerramos el socket del cliente
close
(
client_sockfd
);
exit
(
EXIT_SUCCESS
);
}
// Función principal del servidor TCP
int
main
(
int
argc
,
char
*
argv
[])
{
int
port
,
reutil
=
1
;
struct
sockaddr_in
server_addr
,
client_addr
;
socklen_t
client_len
=
sizeof
(
client_addr
);
bool
continua
=
true
;
// Configuramos el manejador de señal para SIGINT
signal
(
SIGINT
,
signal_handler
);
// Obtenemos el puerto por argumento
if
(
argc
==
3
&&
strcmp
(
argv
[
1
],
"-p"
)
==
0
)
{
port
=
atoi
(
argv
[
2
]);
if
(
port
<=
0
)
{
fprintf
(
stderr
,
"Numero de puerto invalido: %d
\n
"
,
port
);
return
EXIT_FAILURE
;
}
// O lo obtenemos por getservbyname() dando el servicio "daytime"
}
else
if
(
argc
==
1
)
{
struct
servent
*
service
=
getservbyname
(
"daytime"
,
"udp"
);
if
(
service
==
NULL
)
{
fprintf
(
stderr
,
"Error al obtener el puerto para el servicio DAYTIME
\n
"
);
return
EXIT_FAILURE
;
}
port
=
htons
(
service
->
s_port
);
// Si no lo hemos obtenido, notificamos el error
}
else
{
fprintf
(
stderr
,
"Error de Parametros.
\n
Uso: %s [-p puerto]
\n
"
,
argv
[
0
]);
return
EXIT_FAILURE
;
}
// Creamos el socket TCP
if
((
server_sockfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
))
<
0
)
{
perror
(
"Error al crear el socket"
);
return
EXIT_FAILURE
;
}
// Configuramos la dirección del servidor
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_addr
.
s_addr
=
INADDR_ANY
;
server_addr
.
sin_port
=
port
;
// Habilitamos reutilización de direcciones para evitar el problema de puerto en TIME_WAIT
setsockopt
(
server_sockfd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
reutil
,
sizeof
(
reutil
));
// Vinculamos el socket al puerto
if
(
bind
(
server_sockfd
,
(
struct
sockaddr
*
)
&
server_addr
,
sizeof
(
server_addr
))
<
0
)
{
perror
(
"Error en bind()"
);
close
(
server_sockfd
);
return
EXIT_FAILURE
;
}
// Ponemos el socket en modo escucha
if
(
listen
(
server_sockfd
,
10
)
<
0
)
{
perror
(
"Error en listen()"
);
close
(
server_sockfd
);
return
EXIT_FAILURE
;
}
// Imprimimos un mensaje para verificar que se ha creado correctamente
printf
(
"Servidor TCP Daytime en el puerto %d
\n
"
,
port
);
while
(
continua
)
{
// Aceptamos conexiones entrantes
int
client_sockfd
=
accept
(
server_sockfd
,
(
struct
sockaddr
*
)
&
client_addr
,
&
client_len
);
if
(
client_sockfd
<
0
)
{
if
(
errno
==
EINTR
)
{
// Interrupción por señal, salir del bucle
continua
=
false
;
// Cambiamos continua a false para salir del bucle
continue
;
}
perror
(
"Error en accept()"
);
continue
;
}
// Creamos un nuevo proceso para manejar al cliente
pid_t
pid
=
fork
();
if
(
pid
<
0
)
{
perror
(
"Error en fork()"
);
close
(
client_sockfd
);
}
else
if
(
pid
==
0
)
{
// Proceso hijo: manejar al cliente
close
(
server_sockfd
);
// El proceso hijo no necesita el socket del servidor
manejar_cliente
(
client_sockfd
);
}
else
{
// Proceso padre: cerrar el socket del cliente
close
(
client_sockfd
);
// Limpia procesos hijos finalizados
while
(
waitpid
(
-
1
,
NULL
,
WNOHANG
)
>
0
);
}
}
shutdown
(
server_sockfd
,
SHUT_RDWR
);
close
(
server_sockfd
);
// Cerramos el socket principal al salir del bucle
return
0
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment