67638


C言語でミドルウェア(データストア)にクエリを投げて結果を得るプログラムを自作しています。

最初は fputs(3) や fgets(3)
で行ごとに気楽にやっていたのですが、テキストじゃないバイナリデータでのやり取りが必要なクエリを扱う際にバグりました。

そこで send(2) や recv(2) に切り替えたのですが、今度は一回の recv(2) で得られたクエリ結果が中途半端な箇所で欠けていて、再度
recv(2) で取りに行かないといけなくなりました。

しかしもう全部クエリ結果を取り終えた状態で再度 recv(2) を呼ぶと、設定したタイムアウトまでブロックが発生して使い物にならなくなりました。

recv(2) で得られるクエリ結果の欠け方が毎回違って困りました。単純な while ループでやると上記ブロッキング問題に悩まされました。

最終的に 1 byte ずつ見て行きながら期待するクエリ結果が全部取得できたかどうか判断するしかありませんでした。

この recv(2)
を用いたサーバーからの受信プログラムにおいて、1回のリクエストでレスポンスを全部受信できたかどうかを判断する良い方法はあるのでしょうか。今回の例でいうとミドルウェアのプロトコルのパース結果で判断せざるを得ないのでしょうか。それとも取得待ちのデータがあるかどうかを判断できる便利な関数や方法がありますか？
そもそもノンブロッキングで実装した方がシンプルに書けるのでしょうか。

自分はC言語の鍛錬がまだ浅くモヤモヤしています。見当違いな質問でしたら恐縮ですがご教示いただけますと幸いです。

作成したプログラムは [redis-cluster-data-
transfer](https://github.com/supercaracal/redis-cluster-data-transfer)
で、ミドルウェアのプロトコルは [RESP2](https://redis.io/topics/protocol) です。


CC BY-SA 4.0
2020-06-12T10:08:59.073
67585
2020-06-13T23:39:30.237
2020-06-12T10:36:02.850
26239
26239
question
c redis
C言語で recv(2) でサーバーから受信するときの切れ目の判別法に関しまして


ブロックされて困るのであれば、

[code]

    int val = 1;
    ioctl(sock, FIONBIO, &val);
    
[/code]

でノンブロッキングソケットとすることです。この場合、`recv`は受信済みバッファに受信済みのデータのみが読み出せることになり、待つことはありません。もし受信バッファが空の場合、何も読み出せないため`recv`はエラーを返すことになるため、適切に対処する必要があります。

それと当然ですが、`recv`は待たなくなるためタイムアウトの設定は意味を成さなくなり、ご自身で時間管理する必要があります。


CC BY-SA 4.0
2020-06-12T13:58:59.770
67599
2020-06-12T13:58:59.770
4236
67585
answer


> 1回のリクエストでレスポンスを全部受信できたかどうかを判断する良い方法はあるのでしょうか。

ソケットの方ではこれを判定するのは不可能です。  
長いデータは分割して読まれ、短いデータは一緒くたに読まれ、コンフリクトが起きれば遅れて読まれます。

ソケットに流すデータのフォーマットとしてデータ長を含めておいて、その分のデータが受信されたか否かで判断する必要があります


CC BY-SA 4.0
2020-06-13T23:39:30.237
67638
2020-06-13T23:39:30.237
27481
67585
answer