今日のテスト
C++自宅のWindows11とサーバーLINUX間のUDP通信(2023/09/03)
→目次

自宅の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側は受信できません!

Windows11側のプロスラムは以下の通りですです。
#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
以上です。