2018/05/13

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

AF_UNIX comes to Windows – Windows Command Line Tools For Developers

Introduction:   Beginning in Insider Build 17063 , you’ll be able to use the unix socket ( AF_UNIX )...

https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows/

昨日、Windows 10 April 2018 Update が来た。WSL (Windows Subsystem for Linux) の常駐もちゃんと動く様になってた。仕組みはどうやら WSL 上のプロセスが一つでも生きていればバックグラウンドで Ubuntu.exe が生き続けてくれるという物らしい。WSL でも tmux が問題なく使える様になって開発しやすくなった。

ところでこの Windows 10 April 2018 Update には、開発者が待ちに待った Windows での AF_UNIX 対応が入っている。つまりは UNIX Domain Socket が Windows で動く様になったという事だ。物は試しと簡単なプログラムを作ってみた。 #ifdef _WIN32
# include <ws2tcpip.h>
# include <io.h>
#else
# include <sys/fcntl.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# define closesocket(fd) close(fd)
#endif
#include <stdio.h>

#define UNIX_PATH_MAX 108

typedef struct sockaddr_un {
  ADDRESS_FAMILY sun_family;
  char sun_path[UNIX_PATH_MAX];
} SOCKADDR_UN, *PSOCKADDR_UN;

int
main(int argc, char* argv[]) {
  int server_fd;
  int client_fd;
  struct sockaddr_un server_addr; 
  size_t addr_len;

#ifdef _WIN32
  WSADATA wsa;
  WSAStartup(MAKEWORD(22), &wsa);
#endif

  unlink("./server.sock");

  if ((server_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    perror("server: socket");
    exit(1);
  }

  memset((char *) &server_addr, 0sizeof(server_addr));
  server_addr.sun_family = AF_UNIX;
  strcpy(server_addr.sun_path, "./server.sock");

  if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
    perror("server: bind");
    exit(1);
  }

  if (listen(server_fd, 5) < 0) {
    perror("server: listen");
    closesocket(server_fd);
    exit(1);
  }

  while (1) {
    if ((client_fd = accept(server_fd, NULLNULL)) < 0) {
      perror("server: accept");
      break;
    }
    while (1) {
      char buf[256];
      int n = recv(client_fd, buf, sizeof(buf), 0);
      if (n <= 0break;
      buf[n] = 0;
      puts(buf);
    }
    closesocket(client_fd);
  }

  closesocket(server_fd);

#ifdef _WIN32
  WSACleanup();
#endif
}

普通のソケットプログラムだ。mingw のヘッダには sockaddr_un の定義が無いので冒頭で宣言している。Visual Studio だと afunix.h というヘッダが入るはず。Windows はソケットディスクリプタに対して read/write/close が動作しないのはこれまで通りだった。次にクライアントのコード。

#ifdef _WIN32
# include <ws2tcpip.h>
# include <io.h>
#else
# include <sys/fcntl.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# define closesocket(fd) close(fd)
#endif
#include <stdio.h>

#define UNIX_PATH_MAX 108

typedef struct sockaddr_un {
  ADDRESS_FAMILY sun_family;
  char sun_path[UNIX_PATH_MAX];
} SOCKADDR_UN, *PSOCKADDR_UN;

int
main(int argc, char* argv[]) {
  int client_fd;
  struct sockaddr_un client_addr; 

#ifdef _WIN32
  WSADATA wsa;
  WSAStartup(MAKEWORD(22), &wsa);
#endif

  if ((client_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    perror("server: socket");
    exit(1);
  }

  memset((char *) &client_addr, 0sizeof(client_addr));
  client_addr.sun_family = AF_UNIX;
  strcpy(client_addr.sun_path, "./server.sock");

  if (connect(client_fd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) {
    perror("client: connect");
    exit(1);
  }

  while (1) {
    char buf[256];
    if (!fgets(buf, sizeof(buf), stdin))
      break;
    char *p = strpbrk(buf, "\r\n");
    if (p) *p = 0;
    if (send(client_fd, buf, strlen(buf), 0) < 0)
      break;
  }

  closesocket(client_fd);

#ifdef _WIN32
  WSACleanup();
#endif
}

こちらも至って普通のコード。一応 UNIX でもコンパイル出来る様にしたつもりだけど、試してはない。

AF_UNIX

mingw でも問題なくコンパイルして動作する様になったし、実行は Cygwin も msys2 も WSL も必要なく動作した。Windows 10 でしか動作しないので、しばらくは OSS で使われる事はないだろうけど、UAC の画面も開かないので個人的には便利だと思う。今後は Windows 版の nginx がリバースプロキシ対応したりするんじゃないかと思う。

Posted at by