2011-10-23 20 views
2

Dプログラミング言語で書かれたアプリのブラウザでの表示を更新したいと考えています。ブラウザは、入力データをアプリに送り返す必要があります。Dアプリとブラウザ間の双方向通信を可能にするツールチェーン

私はプログラミングにまだまだ慣れていて、ソケット/ウェブソケット/サーバーがどのように適合しているかと混同しています。誰かがアプローチを提案することはできますか?

+0

あなたはどのように私はDでWebアプリケーションを書くことができます」、求めているように聞こえますか? "あなたは、ソケット、サーバーなどについて混乱していると言います...もしあなたがDウェブアプリケーションを書こうとしているなら、これはおそらく入り口になるでしょう。 D Webアプリケーションを書くためのいくつかの興味深いサードパーティ製の(非標準ライブラリの)ツールがありますが、Webサーバーの仕組みやWebサーバーが既にインストールされていることを熟知していると思います。アプリケーションを展開します。 – gmfawcett

+0

あなたはこの質問の答えをチェックしたいかもしれません:http://stackoverflow.com/questions/7652372/using-d-how-would-i-listen-to-incoming-http-requests-and-respond-to ---------- – gmfawcett

+0

@gmfawcettあなたの例をありがとう! – timboy

答えて

2

gmfawcettの基本的なDサーバーの例のおかげで、他の場所で見つかったバージョン8仕様のベアボーンwebsocket実装と仲良くしてくれてありがとうございます(現在Chrome 14/15でしか動作しません。 )。それはかなりcut'n'pasteしかし十分にうまくいくようであり、私はそれが私の必要性を提供するのに十分であることを期待する。

誰も私のコードを素早く見てみようとする傾向がある場合は、どうぞお気軽にお寄せください。ありがとうございます!

ベアボーンのWebSocketのimpl:http://blog.vunie.com/implementing-websocket-draft-10

のWebSocket V8仕様(プロトコル-17):http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17

module wsserver; 

import std.algorithm; 
import std.base64; 
import std.conv; 
import std.stdio; 
import std.socket; 
import std.string; 

//std.crypto: https://github.com/pszturmaj/phobos/tree/master/std/crypto 
import crypto.hash.base; 
import crypto.hash.sha; 

struct WsServer 
{ 
    private 
    { 
     Socket s; 
     Socket conn; 
     string subProtocol; 
    } 

    this(string host, ushort port = 8080, string subProtocol = "null") 
    { 
     this.subProtocol = subProtocol; 

     s = new TcpSocket(AddressFamily.INET); 
     s.bind(new InternetAddress(host, port)); 
     s.listen(8); 

     conn = s.accept(); 

     writeln("point/refresh your browser to \"http://", host, "\" to intiate the websocket handshake"); 

     try 
     { 
      initHandshake(conn); 
     } 
     catch (Throwable e) 
     { 
      stderr.writeln("thrown: ", e); 
     } 
    } 

    ~this() 
    { 
     conn.shutdown(SocketShutdown.BOTH); 
     conn.close(); 

     s.shutdown(SocketShutdown.BOTH); 
     s.close(); 
    } 

    string data() 
    { 
     ubyte[8192] msgBuf; 
     auto msgBufLen = conn.receive(msgBuf); 

     auto firstByte = msgBuf[0]; 
     auto secondByte = msgBuf[1]; 

     // not sure these two checks are woking correctly!!! 
     enforce((firstByte & 0x81), "Fragments not supported"); // enforce FIN bit is present 
     enforce((secondByte & 0x80), "Masking bit not present"); // enforce masking bit is present 

     auto msgLen = secondByte & 0x7f; 

     ubyte[] mask, msg; 

     if(msgLen < 126) 
     { 
      mask = msgBuf[2..6]; 
      msg = msgBuf[6..msgBufLen]; 
     } 
     else if (msgLen == 126) 
     { 
      mask = msgBuf[4..8]; 
      msg = msgBuf[8..msgBufLen]; 
     } 

     foreach (i, ref e; msg) 
      e = msg[i]^mask[i%4]; 

     debug writeln("Client: " ~ cast(string) msg); 

     return cast(string) msg; 
    } 

    void data(string msg) 
    { 
     ubyte[] newFrame; 

     if (msg.length > 125) 
      newFrame = new ubyte[4]; 
     else 
      newFrame = new ubyte[2]; 

     newFrame[0] = 0x81; 

     if (msg.length > 125) 
     { 
      newFrame[1] = 126; 

      newFrame[2] = cast(ubyte) msg.length >> 8; 
      newFrame[3] = msg.length & 0xFF; 
     } 
     else 
      newFrame[1] = cast(ubyte) msg.length; 

     conn.send(newFrame ~= msg); 

     debug writeln("Server: " ~ msg); 
    } 

    private void initHandshake(Socket conn) 
    { 
     ubyte[8192] buf; // big enough for some purposes... 
     size_t position, headerEnd, len, newpos; 

     // Receive the whole header before parsing it. 
     while (true) 
     { 
      len = conn.receive(buf[position..$]); 

      debug writeln(cast(string)buf); 

      if (len == 0)    // empty request 
       return; 

      newpos = position + len; 
      headerEnd = countUntil(buf[position..newpos], "\r\n\r\n"); 
      position = newpos; 

      if (headerEnd >= 0) 
       break; 
     } 

     // Now parse the header. 
     auto lines = splitter(buf[0..headerEnd], "\r\n"); 
     string request_line = cast(string) lines.front; 
     lines.popFront; 

     // a very simple Header structure. 
     struct Pair 
     { 
      string key, value; 

      this(ubyte[] line) 
      { 
       auto tmp = countUntil(line, ": "); 
       key = cast(string) line[0..tmp]; // maybe down-case these? 
       value = cast(string) line[tmp+2..$]; 
      } 
     } 

     Pair[] headers; 
     foreach(line; lines) 
      headers ~= Pair(line); 

     auto tmp   = splitter(request_line, ' '); 
     string method  = tmp.front; tmp.popFront; 
     string url   = tmp.front; tmp.popFront; 
     string protocol  = tmp.front; tmp.popFront; 

     enum GUID_v8 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // version 8 spec... might change 
     auto sha1 = new SHA1; 
     sha1.put(strip(headers[5].value) ~ GUID_v8); 
     auto respKey = to!string(Base64.encode(sha1.finish())); 

     // Prepare a response, and send it 
     string resp = join(["HTTP/1.1 101 Switching Protocols", 
          "Upgrade: websocket", 
          "Connection: Upgrade", 
          "Sec-WebSocket-Accept: " ~ respKey, 
          "Sec-WebSocket-Protocol: " ~ subProtocol, 
          ""], 
          "\r\n"); 

     conn.send(cast(ubyte[]) (resp ~ "\r\n")); 

     debug writeln(resp); 
    } 
} 
関連する問題