自宅のPCとさくらVPS間でUDP通信のC++テストプログラムを作ってテストしました。 テストの環境は、自宅のPC側がWindows11/vc++で、さくらVPS側がRocky Linux9/c++です。 送信・受信の流れは以下の通りです。 さくらVPS:自宅のPCから受信を待つ。 自宅のPC側:さくらVPSへソケット送信する。さくらVPSからの返信を待つ。 さくらVPS:受信データを取り出す。送信元のIPアドレス:ポートへ返信する。 自宅のPC側:さくらVPSからの返信を受信する。ポイント:通信は自宅のWiFiやルーター等を経由するので、 IPアドレス変換機能が働いています。 そのため、さくらVPS側が送信元のIPアドレス:ポートへ返信しなければ、自宅のPC側は受信できません! #include <windows.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") #pragma warning(disable:4996) using namespace std; int main(int argc, char** argv) { SetConsoleOutputCP(CP_UTF8); WORD ver = MAKEWORD(2, 2); WSADATA wsa; if (WSAStartup(ver, &wsa) != 0) { cout << "WSAStartup error\r\n"; } int sd; // UDPソケットを作成 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return -1; } // バインドする用の待ち受けるIPソドレスとポート番号 struct sockaddr_in own_addr; own_addr.sin_family = AF_INET; own_addr.sin_port = htons(5005); own_addr.sin_addr.s_addr = INADDR_ANY; printf("for bind own port=%d\n", ntohs(own_addr.sin_port)); printf("for bind own addr=%s\n", inet_ntoa(own_addr.sin_addr)); if (bind(sd, (struct sockaddr*)&own_addr, sizeof(own_addr)) < 0) { perror("bind"); return -1; } // 送信先(さくらVPS)アドレスとポート番号を設定する struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(5001); addr.sin_addr.s_addr = inet_addr("153.121.nnn.nnn"); printf("send to port=%d\n", ntohs(addr.sin_port)); printf("send to addr=%s\n", inet_ntoa(addr.sin_addr)); // さくらVPSへ送信 const char* mess = "i love you."; if (sendto(sd, mess, strlen(mess), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("sendto"); return -1; } printf("さくらVPSへ「%s」を送信しました。\n", mess); // さくらVPSから受信を待ち、受信する char buf[2048]; memset(buf, 0, sizeof(buf)); struct sockaddr_in from_addr; int sin_size = sizeof(from_addr); printf("さくらVPSから返信を待っている.......\n"); if (recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&from_addr, &sin_size) < 0) { perror("recvfrom"); return -1; } printf("from sakura sin_port=%d\n", ntohs(from_addr.sin_port)); printf("from sakura ipaddr=%s\n", inet_ntoa(from_addr.sin_addr)); printf("さくらVPSから返信 = 「%s」\n", buf); closesocket(sd); WSACleanup(); cout << "おわり!\n"; return 0; }さくらVPS側のプロスラムかは以下の通りですです。 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> int main(int argc, char** argv) { // ソケット int sd; // 待ち受けるIPソドレスとポート番号 struct sockaddr_in waiting_addr; // from_addr には、送信元アドレスとポートが格納 struct sockaddr_in from_addr; // UDPソケットを作成 if((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return -1; } waiting_addr.sin_family = AF_INET; waiting_addr.sin_port = htons(5001); waiting_addr.sin_addr.s_addr = INADDR_ANY; printf("waiting port=%d\n", ntohs(waiting_addr.sin_port)); printf("waiting addr=%s\n", inet_ntoa(waiting_addr.sin_addr)); // バインドする if(bind(sd, (struct sockaddr *)&waiting_addr, sizeof(waiting_addr)) < 0) { perror("bind"); return -1; } // 受信待ち、受信する printf("Windows11の送信を待っている.......\n"); char buf[2048]; memset((char *)buf, 0, sizeof(buf)); socklen_t sin_size = sizeof(from_addr); if(recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&from_addr, &sin_size) < 0) { perror("recvfrom"); return -1; } printf("Windows11からを受信した = 「%s」\n", buf); printf("from windows11 port=%d\n", ntohs(from_addr.sin_port)); printf("from windows11 ipaddr=%s\n", inet_ntoa(from_addr.sin_addr)); // 受信したソケットのIPアドレス:ポートへ返信する strcat(buf, "をありがとう。"); if (sendto(sd, buf, strlen(buf), 0, (struct sockaddr*)&from_addr, sizeof(from_addr)) < 0) { perror("sendto"); return -1; } // ソケットをクローズ close(sd); return 0; }Windows11側のプロスラムの実行結果は下記の通りです。 for bind own port=5005 for bind own addr=0.0.0.0 send to port=5001 send to addr=153.121.nnn.nnn さくらVPSへ「i love you.」を送信しました。 さくらVPSから返信を待っている....... from sakura sin_port=5001 from sakura ipaddr=153.121.nnn.nnn さくらVPSから返信 = 「i love you.をありがとう。」 おわり!さくらVPS側のプロスラムの実行結果は下記の通りです。 waiting port=5001 waiting addr=0.0.0.0 Windows11の送信を待っている....... Windows11からを受信した = 「i love you.」 from windows11 port=5005 from windows11 ipaddr=122.103.xxx.xxx以上です。 |