Algunas consideraciones y optimizaciones en llamadas al sistema de puerto serial (lectura, escritura)

prefacio

En la programación que involucra llamadas al sistema, los descriptores de archivos operativos, como tuberías, obtienen nodos de dispositivos y similares (como puertos serie, puertos USB que usan usb como cámara) e involucran la lectura de datos en modo kernel y modo usuario. En este momento, a menudo se encuentra que la lectura y la escritura no pueden cumplir con el ideal. El método de escritura de este artículo primero enumera los puntos problemáticos y luego brinda las soluciones correspondientes.

Este artículo se centra principalmente en las precauciones de llamada al sistema, continuará...


Ayer (7 de julio de 2022), un amigo de Shanghái me preguntó sobre el puerto serie. El modelo de extremo receptor que usaba era select+read. El extremo emisor era RFID que enviaba datos todo el tiempo, y la frecuencia de envío era 10 hz. El la recepción no se almacenó en el búfer. Luego, analícelo, lo que da como resultado paquetes adhesivos para los datos leídos.

1. Problemas y manejo

En la programación del puerto serie, incluso si utiliza select复用IOel método para obtener datos legibles en el estado del kernel, es posible que no pueda obtener los resultados que desea. Por ejemplo, se calcula que se necesitan leer 10 bytes (teóricamente, según el protocolo privado, 10 bytes es un paquete completo), y existe cierta probabilidad de que se lean datos de menos de 10 bytes, la razón es que

内核中用于套接字的缓冲区可能已达到了极限。, todo lo que se requiere en este punto es que la persona que llama vuelva a llamar a la función de lectura o escritura para ingresar o generar los bytes restantes.

Por lo tanto, utilice las siguientes alternativas para este problema:
mediante este método, se puede satisfacer el tamaño de los datos que desea leer. Si los datos leídos son menores que n, significa que el otro extremo de la comunicación del puerto serie ha perdido un paquete. y el
paquete solo se puede descartar.
leer:

ssize_t						/* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
	size_t	nleft;
	ssize_t	nread;
	char	*ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;		/* and call read() again */
			else
				return(-1);
		} else if (nread == 0)
			break;				/* EOF */

		nleft -= nread;
		ptr   += nread;
	}
	return(n - nleft);		/* return >= 0 */
}
/* end readn */

Escribir:

ssize_t						/* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
	size_t		nleft;
	ssize_t		nwritten;
	const char	*ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;		/* and call write() again */
			else
				return(-1);			/* error */
		}

		nleft -= nwritten;
		ptr   += nwritten;
	}
	return(n);
}
/* end writen */

2. Use la función recv en lugar de la función readn

Continuará...

3. pensar

¿ Por qué las funciones readn y writenn convierten void en punteros char ?

En el estándar ANSI C, no está permitido realizar operaciones aritméticas en punteros vacíos, como pvoid++ o pvoid+=1, etc. Debe convertirse en un puntero de tipo char para realizar operaciones de suma y resta en punteros.2.c:17:8: error: invalid use of void expression *p = *pa;

root@ubuntu:/opt/socket/unpv13e/intro# cat 2.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
	char a[10]  = {0};
	memcpy(a, "12345", strlen("12345"));
	char *pa = a;
	void *p = (void*)calloc(1, 10);
	void *p1 = p;	// notice 
	if(p)
	{
		for(; *pa != '\0'; pa++, p++)	{
				*p = *pa;
		}
		printf("p1:%s\n", p1);
		free(p1); p1 = 0;
	}
	return 0;
}
root@ubuntu:/opt/socket/unpv13e/intro# gcc -o readn 2.c 
2.c: In function ‘main’:
2.c:17:5: warning: dereferencing ‘void *’ pointer
     *p = *pa;
     ^~
2.c:17:8: error: invalid use of void expression
     *p = *pa;
        ^
2.c:23:15: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘void *’ [-Wformat=]
   printf("p1:%s\n", p1);

Supongo que te gusta

Origin blog.csdn.net/nc_linux/article/details/125077719
Recomendado
Clasificación