采用akka2.0 IO ByteString相关技术,代码改自http://doc.akka.io/docs/akka/2.0/scala/io.html,目前代码比较粗糙,但性能已经体现出来了。
话不多说,贴代码
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.docs.io.v2
//#imports
import akka.actor._
import akka.util.{ ByteString, ByteStringBuilder }
import java.net.InetSocketAddress
//#imports
//#actor
class HttpServer2(port: Int) extends Actor {
val state = new scala.collection.mutable.HashMap[IO.Handle, ActorRef]()
override def preStart {
IOManager(context.system) listen new InetSocketAddress(port)
}
def receive = {
case IO.NewClient(server) ⇒
val socket = server.accept()
val worker = context.actorOf(Props(new Worker(socket)))
state(socket) = worker
state(socket) ! socket
case IO.Read(socket, bytes) ⇒
state(socket) ! IO.Read(socket, bytes)
case IO.Closed(socket, cause) ⇒
state(socket) ! IO.Closed(socket, cause)
state -= socket
}
}
class Worker(socket: IO.SocketHandle) extends Actor {
val state = IO.IterateeRef.Map.async[IO.Handle]()(context.dispatcher)
override def preStart {
// state(socket) flatMap (_ ⇒ HttpServer2.processRequest(socket))
}
def receive = {
case socket:IO.SocketHandle ⇒
state(socket) flatMap (_ ⇒ HttpServer2.processRequest(socket))
case IO.Read(socket, bytes) ⇒
state(socket)(IO Chunk bytes)
case IO.Closed(socket, cause) ⇒
state(socket)(IO EOF None)
state -= socket
}
}
//#actor
//#actor-companion
object HttpServer2 {
import HttpIteratees._
def processRequest(socket: IO.SocketHandle): IO.Iteratee[Unit] =
IO repeat {
for {
request ← readRequest
} yield {
val rsp = request match {
case Request("GET", "ping" :: Nil, _, _, headers, _) ⇒
OKResponse(ByteString("<p>pong</p>"),
request.headers.exists { case Header(n, v) ⇒ n.toLowerCase == "connection" && v.toLowerCase == "keep-alive" })
case req ⇒
OKResponse(ByteString("<p>" + req.toString + "</p>"),
request.headers.exists { case Header(n, v) ⇒ n.toLowerCase == "connection" && v.toLowerCase == "keep-alive" })
}
socket write OKResponse.bytes(rsp).compact
if (!rsp.keepAlive) socket.close()
}
}
}
//#actor-companion
//#request-class
case class Request(meth: String, path: List[String], query: Option[String], httpver: String, headers: List[Header], body: Option[ByteString])
case class Header(name: String, value: String)
//#request-class
//#constants
object HttpConstants {
val SP = ByteString(" ")
val HT = ByteString("\t")
val CRLF = ByteString("\r\n")
val COLON = ByteString(":")
val PERCENT = ByteString("%")
val PATH = ByteString("/")
val QUERY = ByteString("?")
}
//#constants
//#read-request
object HttpIteratees {
import HttpConstants._
def readRequest =
for {
requestLine ← readRequestLine
(meth, (path, query), httpver) = requestLine
headers ← readHeaders
body ← readBody(headers)
} yield Request(meth, path, query, httpver, headers, body)
//#read-request
//#read-request-line
def ascii(bytes: ByteString): String = bytes.decodeString("US-ASCII").trim
def readRequestLine =
for {
meth ← IO takeUntil SP
uri ← readRequestURI
_ ← IO takeUntil SP // ignore the rest
httpver ← IO takeUntil CRLF
} yield (ascii(meth), uri, ascii(httpver))
//#read-request-line
//#read-request-uri
def readRequestURI = IO peek 1 flatMap {
case PATH ⇒
for {
path ← readPath
query ← readQuery
} yield (path, query)
case _ ⇒ sys.error("Not Implemented")
}
//#read-request-uri
//#read-path
def readPath = {
def step(segments: List[String]): IO.Iteratee[List[String]] = IO peek 1 flatMap {
case PATH ⇒ IO drop 1 flatMap (_ ⇒ readUriPart(pathchar) flatMap (segment ⇒ step(segment :: segments)))
case _ ⇒ segments match {
case "" :: rest ⇒ IO Done rest.reverse
case _ ⇒ IO Done segments.reverse
}
}
step(Nil)
}
//#read-path
//#read-query
def readQuery: IO.Iteratee[Option[String]] = IO peek 1 flatMap {
case QUERY ⇒ IO drop 1 flatMap (_ ⇒ readUriPart(querychar) map (Some(_)))
case _ ⇒ IO Done None
}
//#read-query
//#read-uri-part
val alpha = Set.empty ++ ('a' to 'z') ++ ('A' to 'Z') map (_.toByte)
val digit = Set.empty ++ ('0' to '9') map (_.toByte)
val hexdigit = digit ++ (Set.empty ++ ('a' to 'f') ++ ('A' to 'F') map (_.toByte))
val subdelim = Set('!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=') map (_.toByte)
val pathchar = alpha ++ digit ++ subdelim ++ (Set(':', '@') map (_.toByte))
val querychar = pathchar ++ (Set('/', '?') map (_.toByte))
def readUriPart(allowed: Set[Byte]): IO.Iteratee[String] = for {
str ← IO takeWhile allowed map ascii
pchar ← IO peek 1 map (_ == PERCENT)
all ← if (pchar) readPChar flatMap (ch ⇒ readUriPart(allowed) map (str + ch + _)) else IO Done str
} yield all
def readPChar = IO take 3 map {
case Seq('%', rest @ _*) if rest forall hexdigit ⇒
java.lang.Integer.parseInt(rest map (_.toChar) mkString, 16).toChar
}
//#read-uri-part
//#read-headers
def readHeaders = {
def step(found: List[Header]): IO.Iteratee[List[Header]] = {
IO peek 2 flatMap {
case CRLF ⇒ IO takeUntil CRLF flatMap (_ ⇒ IO Done found)
case _ ⇒ readHeader flatMap (header ⇒ step(header :: found))
}
}
step(Nil)
}
def readHeader =
for {
name ← IO takeUntil COLON
value ← IO takeUntil CRLF flatMap readMultiLineValue
} yield Header(ascii(name), ascii(value))
def readMultiLineValue(initial: ByteString): IO.Iteratee[ByteString] = IO peek 1 flatMap {
case SP ⇒ IO takeUntil CRLF flatMap (bytes ⇒ readMultiLineValue(initial ++ bytes))
case _ ⇒ IO Done initial
}
//#read-headers
//#read-body
def readBody(headers: List[Header]) =
if (headers.exists(header ⇒ header.name == "Content-Length" || header.name == "Transfer-Encoding"))
IO.takeAll map (Some(_))
else
IO Done None
//#read-body
}
//#ok-response
object OKResponse {
import HttpConstants.CRLF
val okStatus = ByteString("HTTP/1.1 200 OK")
val contentType = ByteString("Content-Type: text/html; charset=utf-8")
val cacheControl = ByteString("Cache-Control: no-cache")
val date = ByteString("Date: ")
val server = ByteString("Server: Akka")
val contentLength = ByteString("Content-Length: ")
val connection = ByteString("Connection: ")
val keepAlive = ByteString("Keep-Alive")
val close = ByteString("Close")
def bytes(rsp: OKResponse) = {
new ByteStringBuilder ++=
okStatus ++= CRLF ++=
contentType ++= CRLF ++=
cacheControl ++= CRLF ++=
date ++= ByteString(new java.util.Date().toString) ++= CRLF ++=
server ++= CRLF ++=
contentLength ++= ByteString(rsp.body.length.toString) ++= CRLF ++=
connection ++= (if (rsp.keepAlive) keepAlive else close) ++= CRLF ++= CRLF ++= rsp.body result
}
}
case class OKResponse(body: ByteString, keepAlive: Boolean)
//#ok-response
//#main
object Main extends App {
val port = Option(System.getenv("PORT")) map (_.toInt) getOrElse 8080
val system = ActorSystem()
val server = system.actorOf(Props(new HttpServer2(port)))
}
//#main
分享到:
相关推荐
duilian_writen.py
使用recv_peek实现按行读取readline(只能用于socket)
引用:Windows系统有时之所以会频繁受到损伤,主要是许多应用程序常常共享调用一些DLL文件,一旦有的应用程序在使用完毕被自动卸载掉后,这些应用程序所调用的DLL文件往往也会跟着被删除掉了,这么一来Windows系统或...
a good book writen by Simon
void writen_dat(uchar dat) //1602写数据 { lcdrs=1; P0=dat; delay(1); lcden=1; delay(1); lcden=0; } void main(); void cheak_mima() //检查第二次确认密码是否与第一次相同 { if(q1==w1) { if(q2==w2...
嵌入式实时操作系统μCOS分析与实践 写于2011,2012年2月正式出版 原书的全部课件PPT,1-7章 PPT1-7 本人作品欢迎转载
som of soms,writen by Tetsuo Furukawa.
自定义应用层协议实践 发报文时:前四个字节长度+报文内容一次性发送; 收报文时:先读前四个字节,求出报文内容长度;根据长度读数据。 发送结构:
Combining SVMs with Various Feature Selection Strategies writen by 林智人
Codes writen by a geek working in Red Hat China.
Deep C Secrets. Writen by Peter van der Linden.
《The Unix Time Sharing System》 was writen by Dennis and Ken
A program writen by c# to send mail automatically as configuration.
Psychotic’s Unix Bible Writen by Virtual Circuit(PDF)
Lecture Notes on Approximation Algorithms - Volume I, writen by Rajeev Motwani
Clustering, a book, writen by RUI XU and DONALD C. WUNSCH, II
售前服务管理变革之路 Writen by 吴柏臣 非常经典,下之
bezier curve writen by qt5.8 qt5.8 project of bezier, you can open the pro file and compile the project directly it is fully test and reliable. this bezier curve's t factor is 0.5f C++ coede of bezier...
Another article writen by Don Libes for Expect, curing those uncontrollable fits of interaction.