C++11でTCPソケット通信をしています。
運用中に以下のエラーが発生しました。
発生している問題
read()をdo~while中に記述し、返り値が負のときはエラー出力、
0のときはもう一度read()を繰り返すことで、
返り値が正ならば次に進むようにしています。
例えば、1,2,3等の値が取りたいデータとすると、
12345・・・(以下略)
と続けて取得したいのに、
1か2が抜けてしまうという問題が、数時間に1度程度、不定期に発生します。
(ほとんどの場合は正しい結果になる)
1と2に相当するデータは、仕様で決まっている値で、
1は特定の条件、2は読み取るバイト数の決定に必要となります。
該当のソースコード
C++
1//構造体、共用体定義抜粋 2struct CommandSet{ 3 uint8_t command_set[42] 4} 5 6union ControlSet{ 7AngleSet angle; 8CommandSet command; 9}; 10 11struct SocketSet{ 12 int sockFromSvr; 13}
C++
1SocketSet sock; 2void *SvrListner(void *arg) { 3 4 std::unique_ptr<ControlSet> CommandsFromSvr(new ControlSet); 5 6 while (true) { 7 ssize_t rec; 8 do { 9 rec = read(sock.sockFromSvr, &CommandsFromSvr.get()->command.command_set[0], 1); 10 if (rec < 0) { 11 throw SysCallError(errno); 12 } 13 } while (rec <= 0); 14 15 switch ((int)CommandsFromSvr.get()->command.command_set[0]) { 16 case 1: { 17 ssize_t rec; 18 do { 19 rec = read(sock.sockFromSvr, &CommandsFromSvr.get()->command.command_set[0], 1); 20 21 if (rec < 0) { 22 throw SysCallError(errno); 23 } 24 } while (rec <= 0); 25 26 size_t len = 0; 27 28 do { 29 ssize_t rec = read(sock.sockFromSvr , &CommandsFromSvr.get()->command.command_set[len + 1], (int)CommandsFromSvr.get()->command.command_set[0] * 2) - len); 30 if (rec < 0) { 31 throw SysCallError(errno); 32 } else if (rec == 0) { 33 //エラーメッセージ 34 } 35 len += rec; 36 } while (len < ((int)CommandsFromSvr.get()->command.command_set[0] * 2)); 37 38 break; 39 } 40 41 case 2:{ 42 //case 2 の処理 43 break; 44 } 45 } 46 47 } 48 return nullptr; 49} 50 51int NewTCPSocketConnectingTo(char const *addr, uint16_t port) 52 throw (SysCallError) { 53 struct sockaddr_in server; 54 memset(&server, 0, sizeof server); //struct sockaddr_in serverの初期化 55 56 /*接続先指定用構造体の準備*/ 57 server.sin_family = AF_INET; 58 server.sin_port = htons(port); 59 60 inet_pton(AF_INET, addr, &server.sin_addr.s_addr); 61 62 /*サーバに接続*/ 63 int sock = socket(AF_INET, SOCK_STREAM, 0); /*ソケットの作成*/ 64 65 //sockから負の場合のエラー処理 66 if (sock < 0) { 67 throw SysCallError(errno); 68 } 69 70 // connectの戻り値のチェックとエラー処理 71 int conn = connect(sock, (struct sockaddr *) &server, sizeof(server)); 72 if (conn < 0) { 73 throw SysCallError(errno); 74 } 75 return sock; 76 77} 78 79int main() { 80 sock.sockFromSvr = NewTCPSocketConnectingTo("***.***.***.***", 81 PortNum); 82 83 Thread threadForSvr(SvrListener, "SvrListener"); 84 threadForSvr.Run(nullptr); 85 86 threadForSvr.Join(); 87 88 return 0; 89}
試したこと
当初は、最初の2バイトを読む処理にdo~whileを書いておらず、
返り値が0になった場合を考慮していませんでした。
そのことが原因と考え、上記のようにしたのですが、
解決には至りませんでした。
おかしい点など、ご指摘いただければありがたいです。
開発環境
Linux distribution: 2.6.32-754.3.5.el6.i686
OS: Cent OS 6.10
IDE: Eclipse Oxygen.3a Release(4.7.3a)
gcc: 5.3.1