記事ディレクトリ
序文
システムコールを伴うプログラミングでは、パイプなどのファイル記述子を操作してデバイスノードなど(シリアルポート、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);