コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

Windows-Linux間をTCPで通信する

TCPを使ってWindowsとLinux間で通信してみる。
具体的にはWindows上にVirtualboxで仮想マシンを作成しHost-Only-Adapter経由で通信する。

構成

  • サーバ    : Linux CentOS 6, X86_64(64bit) on Virtualbox
  • クライアント : Windows7 (32bit)

プログラム作成

クライアント側

実行バイナリはVisual Studio 2017 で作成。


TCP_Client.cpp

#include "stdafx.h"

#include <stdio.h>
#include <winsock2.h>

#define PORT_NO_SERVER (12345)
#define IP_ADDRESS_SERVER "192.168.100.254"

int main(void)
{
    WSADATA wsaData;
    struct sockaddr_in server;
    SOCKET sfd = -1;
    char buf[32] = { 0 };
    int rc = 0;

    WSAStartup(MAKEWORD(2, 0), &wsaData);

    sfd = socket(AF_INET, SOCK_STREAM, 0);

    server.sin_family = AF_INET;
    server.sin_port = htons(PORT_NO_SERVER);
    server.sin_addr.S_un.S_addr = inet_addr(IP_ADDRESS_SERVER);

    rc = connect(sfd, (struct sockaddr *)&server, sizeof(server));
    if (rc < 0) {
        printf("connect() failed(%d)\n", rc);
        exit(EXIT_FAILURE);
    }

    while (1) {
        memset(buf, 0, sizeof(buf));
        int rs = recv(sfd, buf, sizeof(buf), 0);

        printf("recv %d byte, %s\n", rs, buf);
    }

    WSACleanup();

    return 0;
}


プロジェクトプロパティから入力にws2_32.libを追記してビルドする。

f:id:segmentation-fault:20170226145605p:plain




Windows側のIPアドレスを 192.168.100.0/24のネットワークに設定しておく。

C:> ipconfig

Windows IP 構成

イーサネット アダプター VirtualBox Host-Only Network:

   接続固有の DNS サフィックス . . . :
   IPv4 アドレス . . . . . . . . . . : 192.168.100.1
   サブネット マスク . . . . . . . . : 255.255.255.0
   デフォルト ゲートウェイ . . . . . :

サーバ側


tcp_server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define MAX_CLIENTS (1)
#define MSGBUF_SIZE (1024)

int main(void)
{
    int sfd = -1;
    struct sockaddr_in client;
    int socklen = sizeof(client);
    int ac_sfd = -1;
    int rc = 0;

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(12345),
        .sin_addr = {
            .s_addr = INADDR_ANY,
        },
    };

    /* ソケットの作成 */
    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd < 0) {
        perror("socket");
        goto error_end;
    }

    rc = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
    if (rc < 0) {
        perror("bind");
        goto close_sfd_end;
    }

    rc = listen(sfd, MAX_CLIENTS);
    if (rc < 0) {
        perror("listen");
        goto close_sfd_end;
    }

    /* 要求受付 */
    ac_sfd = accept(sfd, (struct sockaddr *)&client, &socklen);
    if (ac_sfd < 0) {
        perror("accept");
        goto close_sfd_end;
    }

    while (1) {
        /* メッセージ送信 */
        char msgbuf[MSGBUF_SIZE] = "HELLO WORLD!";
        ssize_t ws = write(ac_sfd, msgbuf, strlen(msgbuf));
        if (ws < 0) {
            perror("write");
            goto close_all_end;
        }

        sleep(1);
    }

 close_all_end:
    close(ac_sfd);
 close_sfd_end:
    close(sfd);
 error_end:

    return 0;
}


ソースコードのビルド

$ gcc tcp_server.c -o tcp_server
$ 



こちらも通信インタフェースに同様のネットワークのIPアドレスを設定しておく。

$ ip -a addr
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:8c:e9:83 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.254/24 brd 192.168.100.255 scope global enp0s8
       valid_lft forever preferred_lft forever

実行結果

確かにサーバが送信した文字列をクライアントで受け取れている。

f:id:segmentation-fault:20170226151420p:plain


キャプチャを見ても確かに3WAYハンドシェイクからデータ送信まで行っている。
(ただし、クライアント→サーバのキャプチャは見えてない。理由不明。)

f:id:segmentation-fault:20170226151710p:plain