Closed snemoto-42 closed 10 months ago
参考)書籍「Linuxプログラミングバイブル」第7章エラー処理
・使用可能関数に入っているerrno(関数というよりはグローバル変数)の活用 https://nxmnpg.lemoda.net/ja/2/errno ・下記のシステムコールにてエラーが発生すると、関数自体は-1を返却、エラーを区別できるようにグローバル変数errnoがセットされる ・if (errno == EINTR)で判定し、エラーハンドリングを行う
poll() ・EINTR:シグナル割り込み時に発生、対策は再度accept()を実施
接続受付accept() ・EINTR:シグナル割り込み時に発生、対策は再度accept()を実施 ・ENFILE:高負荷(たくさんのコネクションがあるとき)時に発生、対策は少し待機してclose()でFDコネクション数が減るのを待つ ・ENOBUFS、ENOMEM:メモリの割り当て制限 ・EAGAIN、EWOULDBLOCK:ノンブロッキングソケットの場合に発生、対策は再度accept()を実施
接続connect() ・第2引数のアドレスとリクエスト内容が一致していれば、少し待機して再度connect()。アドレスが異常であればエラー終了 ・EINPROGRESS:処理進行中なのでエラーとしない ・ETIMEOUT:3ウェイハンドシェークにおける応答が時間内に得られなかった場合に発生、少し待機して再度connect() ・ECONNREFUSED:当該ポートでの接続を受け付けていない時に発生、エラー終了する ・EHOSTUNREACH、ENETUNREACH:ルータが到達不可能時に発生、エラー終了する
送信send() ・EAGAIN:ノンブロッキングソケットの場合に発生、対策は再度send()を実施 ・EAGAIN以外:コネクションを閉じてエラー処理、必要であれば再度コネクションを貼り直す ・EPIPE:接続が閉じられるとSIG_PIPEが送られるのでsignal()で無視する。send()の第4引数にMSG_NOSIGNAL/SO_NOSIGPIPEを指定するとEPIPEがセットされる。 ・データが確実に相手に受信されたことを確認するために、send()に対する応答を相手からrecv()で受け取れるようにする
受信recv() ・送信send()と同じ論点 ・recv()時の切断検知、サーバ側でEOF検知後、sleep()してclose()
経路切断検知 ・recv()待ちの状態では相手がclose()しても検知できないので、処理上これ以上データが来なさそうだなと想定する長さでタイムアウト処理して切断してしまう ・recv()は即座に、send()は2回目のsend()で切断を検知 ・実際のデータを送信する前に0バイト送信をして3ウェイハンドシェークが確立されてから、データの送受信を行う?データ送信前に3ウェイハンドシェークを行う必要があるか確認:connect()/recv()で接続が確立されているか確認
参考)書籍「Linuxプログラミングバイブル」第6章送受信のレベルアップ
受信タイムアウト(タイムアウト付き受信を6つの方法で実装) poll()の第3引数にTIMEOUT_SEC定数を渡し、0が返るとタイムアウト。それ以外の場合はreventsメンバでレディまたはエラーになっているか調べてrecv()を行う。 setsocketopt()を使う方法
サイズの大きなデータの扱い ノンブロッキングの場合は、受信recv()、送信send()にてEAGAINが発生するので、リトライする
行単位の受信
select()/poll()/epoll()との組み合わせ
バイナリデータの場合は改行文字がないため、受信して欲しいサイズを指定する
Server.cppにおいてerrnoによるエラーハンドリングを追加したためクローズ
[Mandatory] Checking the value of errno is strictly forbidden after a read or a write operation. [External functs] strerror, gai_strerror,errno
該当しそうなソースコード Server.cpp -Server::initializeServerSocket() : socket()/setsockopt()/bind()/listen() -Server::acceptNewConnection : accept() -Server::receiveRequest : read() ->recv()にすることで第4引数が指定可能、linux以外でも動く、ファイルに対する操作なのかソケットに対する操作なのか -Server::sendResponse() : send() -Server::runEventLoop : poll()