WindowsとLinux間でソケット通信をする(UDP)


# ・開発環境
Windows10
Visual Studio 2022

Linux
Virtual Box Ubuntu 22.04 LTS
VSCode

Linuxが仮想OSだとネットワークの初期状態がNATであるためブリッジ接続にしないといけない

Virtual Boxの場合は変更したい仮想OSを選択し、設定を開いてネットワークを選択
![スクリーンショット 2023-07-10 094919.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3383082/0fa5dec0-c250-fe7f-9e36-a83d90cb1e3e.png)

設定を開いてネットワークを選択。
NATの横にあるドロップダウンを押す。
![スクリーンショット 2023-07-10 095813.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3383082/175c9917-3ebb-f063-cc7e-12c34481b767.png)

ブリッジアダプターを選択。これでOK！
![スクリーンショット 2023-07-10 100043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3383082/1764eb11-5fcd-ca3d-a8e4-9a511df20160.png)


# ソースコード(Windows側)

### ・インクルード 

```C++:UdpClient.cpp
#include <stdio.h>
#include <iostream>
#include <string>
#include <WinSock2.h> 
#include <Windows.h>

#pragma comment(lib, "ws2_32.lib")

// inet_addr()関数で警告が出る場合は以下で警告を無効化する。
#pragma warning(disable:4996)
```

### ・変数＆ソケット作成

```C++:UdpClient.cpp
    //ソケット
    int sock;
    sockaddr_in addr;
    WSAData wsaData;

    
    WSAStartup(MAKEWORD(2, 0), &wsaData);   
    sock = socket(AF_INET, SOCK_DGRAM, 0); 

    //ソケット作成
    sock = socket(AF_INET, SOCK_DGRAM, 0);
```

### ・Linuxに接続

```C++:UdpClient.cpp
    int port = 12345;
    std::cout << "ポート番号を入力" << std::endl;
    std::cin >> port;

    std::string addrNum;
    std::cout << "接続するIPアドレス" << std::endl;
    std::cin >> addrNum;

    std::string name;
    std::cout << "名前" << std::endl;
    std::cin >> name;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.S_un.S_addr = inet_addr(addrNum.c_str());
```
### ・Linuxに文字を送信する
```C++:UdpClient.cpp
    //データ送信
    sendto(sock, name.c_str(), name.size(), 0, (struct sockaddr*)&addr, sizeof(addr));


    for (int i = 0; i < 100; i++) {
        std::cout << "送信する文字を入力してください" << std::endl;
        std::string data;
        std::cin >> data;
        data = name + ":" + data;
        //データ送信
        sendto(sock, data.c_str(), data.size(), 0, (struct sockaddr*)&addr, sizeof(addr));
        
    }
```
### ・ソケットの削除
```C++:UdpClient.cpp
    closesocket(sock);

    WSACleanup();
```

# ・ソースコード(Linux側)
### ・インクルード
```C++:UdpServer.cpp
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include<string>
#include<vector>
#include<iostream>
```
### ・変数作成＆ポート番号入力
```C++:UdpServer.cpp
  int sock = socket(AF_INET, SOCK_DGRAM, 0);

  sock = socket(AF_INET, SOCK_DGRAM, 0); 

    int port=12345;
    std::cout<<"ポート番号を入力"<<std::endl;
    std::cin>>port;

  // アドレス等格納
  sockaddr_in addr;
  addr.sin_family = AF_INET;  //IPv4
  addr.sin_port = htons(port);   //通信ポート番号設定
  addr.sin_addr.s_addr = INADDR_ANY; 
```

### ・接続

```C++:UdpServer.cpp
     bind(sock, (struct sockaddr *)&addr, sizeof(addr));
    
    char buf[100];

    memset(buf, 0, 100);
  
```
### ・送信された文字を表示
```C++:UdpServer.cpp
    recv(sock, buf, 100, 0);
    std::string name=buf;
    std::cout<<name + "がログイン"<<std::endl; 

    for (int i = 0; i < 100; i++) 
    {

        memset(buf, 0, 100);
        recv(sock, buf, 100, 0);
    
        std::cout<<buf<<std::endl;

    }
  
   close(sock); 

```

ちなみに今回はLinuxとWindowsの片方送信だったけど双方向をする場合はWindows側のファイアーウォール設定をしていないと、windowsからLinuxへのデータの送信が行えません。

コントロールパネルから Windowsファイアウォールを選択。
詳細設定をクリック。

![winFW1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3383082/1e8b050e-9bda-7998-791d-549ef2655395.png)

ファイルとプリンターの共有（エコー要求 － ICMPv4 受信）」をダブルクリック。
![winFW2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3383082/b1f92652-9b47-aa77-4d9e-68304dfdb6b3.png)


「接続を許可する(L)」のラジオボタンにチェックし、「OK」を押下
![winFW3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3383082/7e862ba7-ab8d-1c5d-5734-ac3cbc16cff5.png)


# 終わりに
今回は簡単なWindowsとLinuxの通信をしました。
Linuxが仮想OSだとネットワークの初期状態がNATであるためブリッジ接続にしないといけない
のでそれが分からずにかなり手間取ってしまいました。(・∀・；)