Skip to content

2. Bonus

Sadoming edited this page Dec 18, 2023 · 9 revisions

Soportar Unicode

Por defecto, si desglosas cada caracter en bits con los operadores de bits, puede soportar Unicode.

Recordatorio:

  • Operadores de bits: &, |, ^, ~, << y >>

Para recoger un bit de X pos de un caracter, se usa:

(c >> bit) & 1 // `bit` es una variable que deberias inicializar como 8

Para cambiar un bit de X pos en un caracter, se usa:

ch |= (1 << bit); // `bit` es una variable que deberias inicializar como 7

Confirmar cada señal recibida

Uso de sigaction

Hasta ahora, he usado signal para detectar una señal, pero tambien existe sigaction.

Sigaction

/*
*  sig => Numero de señal
*  act => Estructura sigaction (Que contiene informacion bastante util)
*  oact => Estructura opcional donde se almacenara la accion
*/
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);

En la estructura act hay almacenada si_pid que contiene el PID del que ha mandado la señal.

Pasos para confirmar la señal

  1. En server, cambiaremos signal por sigaction, asi que habra que crear una estructura
int	main(void)
{
	struct sigaction	s_sig; //Esta es la estructura que vamos a necesitar

	ft_printf("PID: %i\n", getpid());
	s_sig.sa_sigaction = ft_print_sig; //Le pasamos la funcion que queremos llamar cuando se detecte una señal
	s_sig.sa_flags = SA_SIGINFO; //SA_INFO comunica con una estructura que detecta el PID del cliente
	sigaction(SIGUSR1, &s_sig, NULL); //LLamamos a sigaction para que detecte SIGUSR1 & SIGUSR2 + la estructura
	sigaction(SIGUSR2, &s_sig, NULL);
	while (1)
		pause();
	return (0);
}
  1. Modificamos la funcion de reconstruir bits => caracter.
    Para que envie una señal cada vez que se reciba SIGUSR1 o SIGUSR2

El PID esta almacenado en si_pid

static void	ft_print_sig(int sig, siginfo_t *t_sig_info, void *oact)
{
	static char	ch;
	static int	bit = 7;

	(void)oact;
	if (bit == 7)
		ch = 0;
	if (sig == SIGUSR2)
		ch |= (1 << bit);
	kill(t_sig_info->si_pid, SIGUSR2); //Enviamos SIGUSR2 al recibir cualquier señal al cliente
	bit--;
	if (bit == -1)
	{
		ft_printf("%c", ch);
		if (!ch)
			kill(t_sig_info->si_pid, SIGUSR1); //Cuando llegamos al final del mensaje, enviamos SIGUSR1.
		bit = 7;
	}
}

Mandamos '\0' desde client una vez lleguemos al final.
El server sabe que el mensaje ha terminado, si detecta este caracter.

  1. Desde el cliente, mandar '\0' al final del mensaje

Aparte, podemos detectar cuando no hay nada en el mensaje y mostrar un error si ocurre.

static int	ft_send_str(char *mess, int pid)
{
	size_t	i;

	i = 0;
	if (!mess || !ft_strllen(mess)) //Detecta si no hay mensaje o si no hay longitud en el mensaje
	{
		ft_printf("Nothing to send\n");
		exit(1);
	}
	while (mess[i])
	{
		if (!ft_send_bits(mess[i], pid))
			return (0);
		usleep(50);
		i++;
	}
	ft_send_bits('\0', pid);
	return (1);
}
  1. Hacer que client tambien este pendiente de si le mandan una señal

Usamos signal para detectar señales, no es necesario usar sigaction.

int	main(int argc, char **args)
{
	int	pid;

	if (argc != 3)
	{
		ft_printf("\033[1;31mWrong number of arguments!\n");
		ft_printf("\033[1;33mRun like these:\n%s <PID> <Message>\n", args[0]);
		exit(1);
	}
	if (!ft_is_all_num(args[1]))
	{
		ft_printf("\033[1;31mPID is invalid!\n");
		exit(1);
	}
	pid = ft_atoi(args[1]);
	signal(SIGUSR1, ft_confirm); //Funcion que llamara al detectar esta señal
	signal(SIGUSR2, ft_confirm);
	if (!ft_send_str(args[2], pid))
	{
		ft_printf("\033[1;31mWrong PID\n");
		exit(1);
	}
	while (1)
		pause();
	return (0);
}

Hay que llamar a signal antes de enviar cualquier señal.

  1. Crear una pequeña funcion para signal
static void	ft_confirm(int sig)
{
	static size_t	bits;

	if (sig == SIGUSR2)
	{
		bits++;
		usleep(50); //Añadimos una pequeña pausa para que no se pierdan algunas señales
	}
	else if (sig == SIGUSR1)
	{
		bits -= 8; //Le resto el caracter '\0', porque no quiero que muestre que ha enviado este caracter.
		ft_printf("Sended %u bits\n", bits);
		exit(0);
	}
}

Clone this wiki locally