###前提・実現したいこと
カメラから取得したRGBデータをネットワーク経由で他のPCへ送信するプログラムを作成しています.
現在通信にはWinsock2でUDP通信を使用しています.
###発生している問題
取得した画素情報を逐次送信した場合,recvfrom()でデータを取りこぼす.
###該当のソースコード
C++
1// Send.cpp 2#include "SocketCom.h" 3#define HEIGHT 480 4#define WIDTH 640 5static char pixelData[3][HEIGHT][WIDTH]; //送信したいピクセルデータ 6 7int main(void){ 8 InitSendSocketCommunication("127.0.0.1", 11111); 9 10 ----- データ格納及びシーケンス番号を付与する処理 ----- 11 12 // 送信処理 13 for (int i = 0; i < HEIGHT ; i++){ 14 SendCharToPartner(pixelData[0][i], sizeof(pixelData[0][i])); 15 SendCharToPartner(pixelData[1][i], sizeof(pixelData[1][i])); 16 SendCharToPartner(pixelData[2][i], sizeof(pixelData[2][i])); 17 } 18 19 return 0; 20}
C++
1// Receive.cpp 2#include "SocketCom.h" 3#define HEIGHT 480 4#define WIDTH 640 5static char pixelData[3][HEIGHT][WIDTH]; //受信したピクセルデータ 6 7int main(void){ 8 InitReceiveSocketCommunication("127.0.0.1", 11111); 9 10 ----- データ格納及びシーケンス番号を付与する処理 ----- 11 12 // 受信処理 13 for (int i = 0; i < HEIGHT ; i++){ 14 ReceiveDataAsChar(pixelData[0][i], ARRAY_SIZE(pixelData[0][i])); 15 ReceiveDataAsChar(pixelData[1][i], ARRAY_SIZE(pixelData[1][i])); 16 ReceiveDataAsChar(pixelData[2][i], ARRAY_SIZE(pixelData[2][i])); 17 18 ----- シーケンス番号を元に対応する配列に格納する処理 ----- 19 } 20 21 return 0; 22}
C++
1// SecketCom.h 2#define UDP_MAX 65507 // UDP通信にて一度に送信することができる最大サイズ 3#define ARRAY_SIZE(arr) ( sizeof(arr) / sizeof(arr[0]) ) // 配列の要素数を返すスクリプト 4 5#include <string> 6using std::string; 7 8// Description: 9// 送信する変数型一覧. 10typedef enum Datatype{ 11 TYPE_INT, 12 TYPE_DOUBLE, 13} Datatype; 14 15// IPアドレスとポート番号で初期化する 16extern bool InitSendSocketCommunication(string IPAdress,int portnumPartner); 17extern bool InitReceiveSocketCommunication( string IPAdress,int portnumPartner); 18extern bool FinalSocketCommunication(); 19extern bool SendStringToPartner(string sendData); 20extern bool SendValueToPartner(void *sendData,int arraySize,Datatype datatype); 21extern bool ReceiveDataAsChar( char *receivedata,int dataSize); 22extern bool ReceiveDataAsValue( void *data,int dataSize,Datatype datatype);
C++
1// SocketCom.cpp 2//============================================================================= 3// include / using / define 4//============================================================================= 5 6// ソケット通信 7#include <winsock2.h> 8// string 9#include "SocketCommunication.h" 10using std::to_string; 11// 文字列出力 12#include <iostream> 13using std::cout; 14using std::endl; 15 16#define STR(var) #var 17#define SEPARATOR "/" 18 19 20//============================================================================= 21// variable 22//============================================================================= 23 24static SOCKET g_sockSend, g_sockReceive; // 送受信の通信プロトコル設定 25static struct sockaddr_in g_addrSend, g_addrReceive; // 送受信のアドレス,ポート設定 26static bool isInitialized = false; 27static int g_socketError = 0; 28static bool g_isBind = false; 29static int sockaddr_in_size; 30 31 32//============================================================================= 33// Static Function 34//============================================================================= 35 36// WinSockのバージョンを指定 37static bool InitWSAData(){ 38 WSADATA wsaData; 39 int error; 40 41 error = WSAStartup(MAKEWORD(2, 0), &wsaData); 42 if (error != 0){ 43 cout << "Winsock WSAStartup Error (SocketCommunication.cpp > InitWSAData())" << endl; 44 cout << STR(error) << endl; 45 46 return false; 47 } 48 isInitialized = true; 49 return true; 50} 51 52//============================================================================= 53// Initialize / Finalize Functions 54//============================================================================= 55 56// 送信の初期化 57bool InitSendSocketCommunication(string IPAdress, int portnumPartner){ 58 59 if (!isInitialized) 60 if (!InitWSAData()) 61 return false; 62 63 // 送信のプロトコルを決める 64 g_sockSend = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 65 g_addrSend.sin_family = AF_INET; 66 g_addrSend.sin_port = htons(portnumPartner); 67 g_addrSend.sin_addr.S_un.S_addr = inet_addr(IPAdress.c_str()); 68 69 return true; 70} 71 72// 受信の初期化 73bool InitReceiveSocketCommunication(string IPAdress, int portnumRecv){ 74 if (!isInitialized) 75 InitWSAData(); 76 77 // 送信のプロトコルを決める 78 g_sockReceive = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 79 g_addrReceive.sin_family = AF_INET; 80 g_addrReceive.sin_port = htons(portnumRecv); 81 g_addrReceive.sin_addr.S_un.S_addr = INADDR_ANY; 82 sockaddr_in_size = sizeof(struct sockaddr_in); 83 84 if (!g_isBind){ 85 g_socketError = bind(g_sockReceive, (struct sockaddr *)&g_addrReceive, sizeof(g_addrReceive)); 86 if (g_socketError != 0){ 87 cout << "Port bind failture! (SocketCommunication.cpp > ReceiveDataAsChar() > bind())" << endl; 88 return false; 89 } 90 g_isBind = true; 91 } 92 char val; 93 int len; 94 95 return true; 96} 97 98// ソケット通信の終了 99bool FinalSocketCommunication(void){ 100 closesocket(g_sockSend); 101 WSACleanup(); 102 103 return true; 104} 105 106 107//============================================================================= 108// Send / Receive Functions 109//============================================================================= 110 111// 文字列の送信 112bool SendStringToPartner(string sendData){ 113 // UDPの限界を超えていないかチェック 114 if (sendData.size() > UDP_MAX){ 115 cout << "Data size is too large! (SocketCommunication.cpp > SendStringToPartner() > string sendData)" << endl; 116 return false; 117 } 118 119 g_socketError = sendto(g_sockSend, sendData.c_str(), sendData.size(), 0, (struct sockaddr *)&g_addrSend, sizeof(g_addrSend)); 120 if (g_socketError == -1){ 121 cout << "Data send failture! (SocketCommunication.cpp > SendStringToPartner() > sendto())" << endl; 122 return false; 123 } 124 125 return true; 126} 127 128// 数値の送信(文字列へ変換して送る) 129bool SendValueToPartner(void *sendData, int arraySize, Datatype datatype){ 130 string buffer; 131 int *bufInt; 132 double *bufDouble; 133 134 switch (datatype){ 135 case TYPE_INT: 136 bufInt = (int*)sendData; 137 138 for (int j = 0; j < arraySize; j++){ 139 buffer += to_string(*(bufInt + j)); 140 buffer += SEPARATOR; 141 } 142 break; 143 case TYPE_DOUBLE: 144 bufDouble = (double*)sendData; 145 146 for (int j = 0; j < arraySize; j++){ 147 buffer += to_string(*(bufDouble + j)); 148 buffer += SEPARATOR; 149 } 150 break; 151 } 152 153 if( !SendStringToPartner(buffer) ) 154 return false; 155 156 return true; 157} 158 159// charデータの受信 160bool ReceiveDataAsChar(char *data, int dataSize){ 161 // UDPの限界を超えていないかチェック 162 if (dataSize > UDP_MAX){ 163 cout << "Data size is too large! (SocketCommunication.cpp > ReceiveDataAsChar() > int dataSize)" << endl; 164 return false; 165 } 166 167 memset(data, 0, dataSize); 168 169 g_socketError = recvfrom(g_sockReceive, data, 1284, 0, (struct sockaddr *)&g_addrReceive, &sockaddr_in_size); 170 if (g_socketError < 0){ 171 cout << "Data receive failture! (SocketCommunication.cpp > ReceiveDataAsChar() > recv())" << endl; 172 cout << "ERROR_CODE:" << WSAGetLastError() << endl; 173 return false; 174 } 175 176 return true; 177} 178 179// 数値データの受信 180bool ReceiveDataAsValue(void *data, int dataSize, Datatype datatype){ 181 char buffer[UDP_MAX]; 182 static char *p; //正直謎ポインタ(for strtok_s()) 183 184 // とりあえずchar型として受け取る 185 if (!ReceiveDataAsChar(buffer, sizeof(buffer))) 186 return false; 187 188 // doubleとかはcharとデータサイズが違うから,数値データ一つ毎にSEPARATORをはさんで送る 189 switch (datatype){ 190 case TYPE_INT: 191 *((int*)data) = atof( strtok_s( buffer, SEPARATOR, &p ) ); 192 for (int i = 1; i < dataSize; i++) 193 *((int*)data + i) = atof(strtok_s(NULL, SEPARATOR, &p)); 194 break; 195 case TYPE_DOUBLE: 196 *((double*)data) = atof( strtok_s( buffer, SEPARATOR, &p ) ); 197 for (int i = 1; i < dataSize; i++) 198 *((double*)data + i) = atof(strtok_s(NULL, SEPARATOR, &p)); 199 break; 200 } 201 202 return true; 203}
###試したこと
送信のforループの中に無意味な処理("for (int h = 0; h < 1000000; h++)")を追加して送信の間隔を空けた場合,取りこぼすことなく受信することができた.しかし速度を重視してUDPを採用したので,可能であれば無意味な処理を使用せず実行したいと考えている.
###補足情報(言語/FW/ツール等のバージョンなど)
IDE
Visual Studio 2013 Express for Windows Desktop

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/01/12 08:38
2017/01/12 08:50