使用D,我将如何监听传入的HTTP请求并对其进行响应?

时间:2011-10-04 18:25:50

标签: http sockets d

使用D,我将如何监听传入的HTTP流量并对其进行响应?

例如(伪代码):

socket = new socket("locahost", 80)
socket.onRequestRecevied(handleRequest);

function response handleRequest(request) {
  //do something with the request and  respond
  request.respond("hello world")
}

我知道除此之外还有很多内容,但我无法找到许多资源来响应传入的http请求。

编辑: 我目前的尝试只产生了“无法创建套接字:不允许操作”等异常。这可能意味着我正确地做了,但我只是收到系统错误信息。

3 个答案:

答案 0 :(得分:5)

它与侦听正常的传入TCP连接并响应它们相同:

  import std.socket;
  Socket s = new TcpSocket(AddressFamily.INET);
  s.bind(new InternetAddress("0.0.0.0", 80));
  s.listen(8);
  while (true) {
    Socket conn=s.accept();
    //handle incoming message (I'm putting it in a task pool to handle ;) )
    taskPool.put(task!handleHttp(conn));
  }

handleHttp(Socket)包含接收http请求的逻辑,并按照http标准发送响应(你必须找到你的自己)

答案 1 :(得分:5)

标准库中目前没有HTTP服务器。 Adam Ruppe有some very good code on Github用于Web工作,但它目前不包括独立的Web服务器。

下面的程序是一个简单的单线程基本HTTP服务器,用于教育 目的。生成有效的HTTP响应仍由您决定;但至少它 解析标题,并让您有机会根据细节做出回应 请求。

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

// usage: ./server port

void main(string[] args)
{
  enum BACKLOG = 8;
  ushort PORT = to!ushort(args[1]);
  Socket s    = new TcpSocket(AddressFamily.INET);
  s.bind(new InternetAddress("0.0.0.0", PORT));
  s.listen(BACKLOG);

  scope (exit) 
  { 
    s.shutdown(SocketShutdown.BOTH);
    s.close();
  }

  while (true)
  {
    debug writeln("waiting...");
    Socket conn = s.accept();
    scope (exit)  
    {
      conn.shutdown(SocketShutdown.BOTH);
      conn.close();
    }
    try
    {
      handleHttp(conn);
    }
    catch (Throwable e) 
    {
      stderr.writeln("thrown: ", e);
    }
  }    
}

void handleHttp(Socket conn)
{
  // Make a buffer big enough to read a full HTTP header. My approach here is to 
  // read the header in its entirety before proceeding. This isn't production
  // quality, but good enough for some applications.

  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..$]);

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

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

    if (headerEnd >= 0) 
      break;
  }

  // Anything beyond headerEnd+4 is part of the request body. For now, bail:
  // no POSTs or PUTs allowed. Feel free to remove the assert & implement them!
  assert (position-(headerEnd+4) == 0, 
          "Sorry, only content-free requests are supported.");

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

  debug writeln(request_line);

  // 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;

  debug writefln("%s, %s, %s", method, url, protocol);

  // Prepare a response, and send it

  string resp = join(["HTTP/1.1 200 OK", 
                      "Content-Length: 2",
                      "Content-Type: text/plain",
                      "Connection: close",
                      "",
                      "OK"],
                     "\r\n");

  conn.send(cast(ubyte[]) resp);
}

答案 2 :(得分:1)

有一个名为G-Wan的多线程(基于事件的)Web服务器,它支持本机 D脚本。

我从未将它与'D'脚本一起使用,只使用了符合预期的C ++脚本。