シリアル ポート システム コール (読み取り、書き込み) における考慮事項と最適化

序文

システムコールを伴うプログラミングでは、パイプなどのファイル記述子を操作してデバイスノードなど(シリアルポート、USBをカメラとして使用するUSB​​ポートなど)を取得し、カーネルモードやユーザーモードでのデータの読み込みを伴います。このとき、読み書きが理想通りにいかないことがよくありますが、この記事の書き方では、まず問題点を列挙し、それに対応する解決策を示します。

この記事ではシステムコールの注意事項を中心に続きます...


昨日 (2022 年 7 月 7 日)、上海の友人がシリアル ポートについて尋ねました。彼が使用した受信側のモデルは select+read でした。送信側は RFID を使用して常にデータを送信し、送信周波数は 10 Hz でした。受信側のモデルは select+read でした。最後がキャッシュされませんでした。その後、それを解析すると、読み取りデータのスティッキー パケットが生成されます。

1. トラブルと対処方法

シリアルポートプログラミングでは、カーネル状態で読み取れるデータを取得する方法を用いてもselect复用IO、意図した結果が得られない場合があります。例えば、10バイトを読み込む必要がある計算になり(理論上、プライベートプロトコルによれば10バイトで完全なパッケージとなる)、一定の確率で10バイト未満のデータが読み込まれることになる。

内核中用于套接字的缓冲区可能已达到了极限。、この時点で必要なのは、呼び出し元が読み取りまたは書き込み関数を再度呼び出して、残りのバイトを入力または出力することだけです。

したがって、この問題に対して次の代替手段を使用してください:
この方法により、読み出したいデータ サイズを満たすことができます. 読み取ったデータが n 未満の場合は、シリアル ポート通信の相手側でパケットが失われたことを意味します。そして
パケットは破棄することしかできません。
読む:

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 */

書く:

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. readn関数の代わりにrecv関数を使用します。

つづく...

3.考える

readn 関数と writenn 関数の両方が void をcharポインタに変換するのはなぜですか?

ANSI C 標準では、pvoid++ や pvoid+=1 などの void ポインターに対して算術演算を実行することは許可されていません。ポインターに対して加算および減算演算を実行するには、char 型ポインターに変換する必要があります。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);

おすすめ

転載: blog.csdn.net/nc_linux/article/details/125077719