English / Japanese

gimite/socket


○概要

TCP/IPとUDP/IPの通信をするためのC++ライブラリです。Windows(WinSock2を使用)、UNIX(POSIX Socketを使用)に対応しています。


○ダウンロード

gimite/socket.h Ver.1.5


○注意

  1. Ver.1.1からserver_socketがserver_stream_socketに変わり、仕様もちょっと変わりました。
  2. Windowsのヘッダによっては、内部でWinsock.hをincludeしてしまい、コンパイルエラーの原因になるものが有ります。先にWinsock2.hをincludeすれば回避できると思います。
  3. gcc 2.9xでは、streambufの形式が古いので使えません。STLPort使えばいいのかも?
  4. リファレンス内で、よく使うメンバにはが付いています。


○例

socket_streamを使えば、ストリームソケットをC++のiostreamとして扱えます。

//例1: 簡易HTTPクライアント
#include <iostream>
#include <gimite/socket.h>

int main()
{
//最初に1回だけ呼び出してください。
gimite::startup_socket();
{
  //www.google.comのポート80(HTTP)に接続。
  gimite::socket_stream sst("www.google.com", 80);
  //エラーチェック。
  if (!sst){
    std::cerr << "Failed to connect." << std::endl;
  }else{
    //文字列を送信。
    sst << "GET / HTTP/1.0\r\n\r\n";
    std::string s;
    //1行ずつ受信して表示。
    while (std::getline(sst, s))
      std::cout << s << std::endl;
    }
  }
  //最後に1回だけ呼び出してください。
  gimite::cleanup_socket();
  return 0;
}

server_stream_socketはサーバ側ストリームソケットをラップしています。

//例2: エコーサーバ
#include <iostream>
#include <gimite/socket.h>

int main()
{
  //最初に1回だけ呼び出してください。
  gimite::startup_socket();
  {
    //ポート12345でクライアントの接続を受け付け始めます。
    gimite::server_stream_socket server(12345);
    //エラーチェック。
    if (!server){
      std::cerr << "Failed to bind socket." << std::endl;
    }else{
      while (true){
        //クライアントからの接続要求を待ち、最初に来た人との
        //通信のためのソケットハンドルを返します。
        gimite::socket_t s= server.accept();
        //クライアントと通信するためのsocket_streamを作成。
        gimite::socket_stream sst(s);
        //ここでは、受信した文字列をオウム返ししています。
        char c;
        while (sst.get(c))
          sst << c;
      }
    }
  }
  //最後に1回だけ呼び出してください。
  gimite::cleanup_socket();
  return 0;
}

datagram_socketはデータグラムソケットをラップしています。

//例3: UDP通信(サーバ側)
#include <iostream>
#include <gimite/socket.h>

int main()
{
  //最初に1回だけ呼び出してください。
  gimite::startup_socket();
  {
    gimite::socket_address saddr;
    //ポート12345にソケットを作成。
    gimite::datagram_socket dsock(12345);
    char cs[5];
    while (true){
      //5バイトのパケットを受信。送信者のアドレスがsaddrに入ります。
      dsock.recvfrom(cs, 5, &saddr);
      //受け取った文字列を表示。
      std::cout << "Message from client: " << cs << std::endl;
      //返事のパケット"pong\0"を送信。
      dsock.sendto("pong", 5, &saddr);
    }
  }
  //最後に1回だけ呼び出してください。
  gimite::cleanup_socket();
  return 0;
}

//例4: UDP通信(クライアント側)
#include <iostream>
#include <gimite/socket.h>

int main()
{
  //最初に1回だけ呼び出してください。
  gimite::startup_socket();
  {
    //送信先アドレスはlocahostのポート12345。
    gimite::socket_address saddr("localhost", 12345);
    //ポート番号はおまかせでソケットを作成。
    gimite::datagram_socket dsock(0);
    //パケット"ping\0"を送信。
    dsock.sendto("ping", 5, &saddr);
    char cs[5];
    //5バイトのパケットを受信。
    dsock.recvfrom(cs, 5);
    //受け取った文字列を表示。
    std::cout << "Message from server: " << cs << std::endl;
  }
  //最後に1回だけ呼び出してください。
  gimite::cleanup_socket();
  return 0;
}


○グローバル関数

bool startup_socket(); ★★

void cleanup_socket(); ★★


○socket_stream

ストリームソケット(TCP)のラッパ。std::iostreamを継承しているので、std::iostreamの入出力機能を使って送受信できる。

socket_stream();

socket_stream(const ip_address& host, int port); ★★

explicit socket_stream(socket_t sock);

virtual ~socket_stream();

void open(const ip_address& host, int port);

void close();

socket_t release();

int send(const void* buffer, int size);

int recv(void* buffer, int size);

socket_t socket()const;

operator void*()const;
bool operator!()const;

*1ただ、そもそもsocket_streamはスレッド安全性を考えてないので、この方法の安全性も怪しいです(汗)。


○server_stream_socket

サーバ側ストリームソケット(TCP)のラッパ。

server_stream_socket();

explicit server_stream_socket(int port, int backlog= 5); ★★

server_stream_socket(socket_t sock, bool is_bound);

~server_stream_socket();

bool bind(int port, int backlog= 5);

socket_t accept(); ★★

void close();

socket_t release();

void socket(socket_t sock, bool is_bound);

socket_t socket()const;

operator const void*()const;
bool operator!()const;


○datagram_socket

データグラムソケット(UDP)のラッパ。

datagram_socket();

explicit datagram_socket(int port); ★★

datagram_socket(socket_t sock, bool is_bound);

~datagram_socket();

bool bind(int port);

int recvfrom(void* buffer, int size, socket_address* addr= 0, int flags= 0); ★★

int sendto(const void* buffer, int size, const socket_address* addr, int flags= 0); ★★

void close();

socket_t release();

void socket(socket_t sock, bool is_bound);

socket_t socket()const;

operator const void*()const;
bool operator!()const;


○ip_address

IPアドレスを表すクラス。ip_addressの代わりに、std::stringやchar*を渡してもOK(例:socket_streamのコンストラクタの引数)。

explicit ip_address(sock_uint32_t addr= INADDR_NONE);

ip_address(const std::string& host);
ip_address(const char* host);
ip_address& operator=(const std::string& host);
ip_address& operator=(const char* host);

in_addr addr()const;

sock_uint32_t as_int()const;


○socket_address

IPアドレスとポート番号の組を表す構造体。

explicit socket_address(const ip_address& i= ip_address(), int p= 0);

ip_address ip;

int port;


○Typedef

型名
意味
Windows
UNIX
socket_t 生のSocket関数群がソケットを区別するために使うハンドル。 SOCKET int
sock_uint32_t IPアドレスを表す32ビット符号無し整数。 unsigned long u_int32_t


○更新履歴

Ver.1.5 2007/4/5 diagram_socketをdatagram_socketに改名。
Ver.1.4 2004/11/3 ip_address、socket_addressに対して「大小と等値の比較」と「ostreamへの出力」ができるように。
Ver.1.3 2004/9/21 '\xff'を受信するとEOFとみなしてしまう場合が有ったのを修正。
Ver.1.2 2004/2/15 socket_stream::send()とsocket_stream::recv()を追加。
Ver.1.1 2003/11/28 server_socketをserver_stream_socketに改名してちょっと仕様変更。
diagram_socketを追加。
ホスト名を直接指定する代わりにip_addressクラスを使うように(文字列からip_addressへの暗黙の型変換が定義されているので、今までの書き方も通る)。
socket_streamを高速化(したつもり)。
Ver.1.0 2003/10/12 公開。


○連絡先

BCB6 Pro、VC.NET Std、VC.NET 2003 Pro、gcc 3.3(cygwin)、gcc 3.3(FreeBSD)で動作確認しました。他の環境での動作確認や、「ここを直したら動いた」などの報告は掲示板にどうぞ。あとバグ報告も。

Gimite 市川