일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- CORDA
- 파이썬 강좌
- 파이썬 데이터분석
- Golang
- 하이브리드앱
- Play2 로 웹 개발
- 안드로이드 웹뷰
- 스칼라 동시성
- play 강좌
- 스칼라 강좌
- 파이썬 머신러닝
- akka 강좌
- 스위프트
- Akka
- Actor
- play2 강좌
- 하이퍼레저 패브릭
- 이더리움
- Hyperledger fabric gossip protocol
- 파이썬
- Play2
- 그라파나
- hyperledger fabric
- 엔터프라이즈 블록체인
- 스칼라
- 파이썬 동시성
- Adapter 패턴
- 플레이프레임워크
- 블록체인
- 주키퍼
- Today
- Total
HAMA 블로그
[Play2] WebSockets 본문
WebSockets
WebSockets 는 웹 브라우저에서 양방향 통신을 가능케 하는 프로토콜 기반으로 사용 될 수 있습니다. (역주: 서버쪽에서 웹브라우저쪽으로도 메세지를 보낸다는 뜻이죠. 기존에는 브라우저에서 서버쪽으로 요청하는 폴링을 주로 사용 했었음) 클라이언트는 메세지를 보낼 수 있으며 서버는 언제라도 메세지를 받을 수 있습니다. 물론 그들 사이에 WebSocket 연결이 액티브 상태일 동안 말이죠.
현재 HTML5 구현이 된 웹 브라우저들은 대부분 자바스크립트 웹소켓 API 를 통한 WebSockets를 지원 하고 있습니다. 그러나 웹소켓이 오직 웹 브라우저에서만 그 의미를 갖는 것은 아닙니다. 많은 웹소켓 클라이언트 라이브러리들을 활용 할 수 있으며 예를들어 서버가 다른 서버와 통신하기 위해서도 사용 할 수 있습니다. 네이티브 모바일 앱과도 말이죠. WebSockets 을 여기서 사용하는것은 플레이 서버가 사용하는 기존 TCP 포트를 재사용할 수 있는 이득을 가져다 줍니다.
WebSockets 조작
지금까지 우리는 Action 인스턴스를 표준 HTTP 요청과 응답을 위해서 사용 하였습니다.
WebSockets 은 전체적으로 다르게 사용되며 표준 Action 을 경유해서 조작되지 않습니다.
플레이는 두가지 다른 방식으로 웹 소켓을 지원하는데 첫번째는 액터를 사용하는것이고 두번째는 iteratees 를 사용하는 것입니다. 양쪽 모두WebSocket 에서 제공된 빌더를 사용합니다.
WebSockets 을 액터와 함께 조작하기
1.WebSocket 의 acceptWithActor 메소드를 사용하여 웹소켓 통신 할 수 있는 환경을 만듭니다. 사용자 정의 액터에 props 의 매개변수로 전달 된 out 즉 외부에 메세지를 전송 할 수 있는 연결 통로를 제공합니다.
import play.api.mvc._
import play.api.Play.current
def socket = WebSocket.acceptWithActor[String, String] { request => out =>
MyWebSocketActor.props(out)
}
acceptWithActor 메소드의 내부는 아래와 같습니다. 궁금하실까봐..복잡합니다. @@
def acceptWithActor[In, Out](f: RequestHeader => HandlerProps)(implicit in: FrameFormatter[In],
out: FrameFormatter[Out], app: Application, outMessageType: ClassTag[Out]): WebSocket[In, Out] = {
tryAcceptWithActor { req =>
Future.successful(Right((actorRef) => f(req)(actorRef)))
}
}
MyWebSocketActor 의 구현은 다음과 같습니다 :
import akka.actor._
object MyWebSocketActor {
def props(out: ActorRef) = Props(new MyWebSocketActor(out))
}
class MyWebSocketActor(out: ActorRef) extends Actor {
def receive = {
case msg: String =>
out ! ("I received your message: " + msg)
}
}
클라이언트에서 보낸 메세지는 사용자 정의 액터에게 보내 질 것입니다. 그리고 다시 메세지를 돌려 줄 수 있습니다. 위의 액터는 메시지를받은 상태에서 클라이언트에서받은 모든 메시지를 간단히 보냅니다.
2. WebSockets 을 iteratees 로 조작하기
액터는 분리 된 메시지를 처리하기위한 더 나은 추상화이지만, iteratees 는 스트림 처리 에있어 더 좋은 추상화입니다. WebSocket 요청을 처리하려면 Action 대신 WebSocket을 사용합니다.
import play.api.mvc._
import play.api.libs.iteratee._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def socket = WebSocket.using[String] { request =>
// Log events to the console
val in = Iteratee.foreach[String](println).map { _ =>
println("Disconnected")
}
// Send a single 'Hello!' message
val out = Enumerator("Hello!")
(in, out)
}
WebSocket은 요청 헤더 (WebSocket 연결을 시작하는 HTTP 요청)에 액세스 할 수 있으므로 표준 헤더와 세션 데이터를 검색 할 수 있습니다. 그러나 요청 본문이나 HTTP 응답에는 액세스 할 수 없습니다. 이 방법으로 WebSocket을 구성 할 때 우리는 in과 out 채널을 모두 반환해야합니다.
- in 채널은 각 메시지에 대해 통지 될 Iteratee [A, Unit] (여기서 A는 메시지 유형 - 여기서 우리는 String을 사용함)이며 소켓이 클라이언트 측에서 닫힐 때 EOF를 수신합니다.
- out 채널은 웹 클라이언트에 보낼 메시지를 생성하는 열거 자 [A]입니다. EOF를 전송하여 서버 측의 연결을 닫을 수 있습니다.
이 예제에서는 각 메시지를 콘솔에 출력하는 간단한 iteratee를 생성합니다. 메시지를 보내려면 간단한 더미 enumerator 를 만들어 하나의 Hello! 메시지를 전송하세요.
Tip: WebSockets 은 https://www.websocket.org/echo.html. 여기서 테스트 가능합니다. 위치는 그냥
ws://localhost:9000
. 로 설정하시구요.
Hello!를 전송 한 직후 입력 데이터를 버리고 소켓을 닫는 다른 예제를 작성해 보겠습니다.
import play.api.mvc._
import play.api.libs.iteratee._
def socket = WebSocket.using[String] { request =>
// Just ignore the input
val in = Iteratee.ignore[String]
// Send a single 'Hello!' message and close
val out = Enumerator("Hello!").andThen(Enumerator.eof)
(in, out)
}
다음은 입력 데이터가 표준 출력에 기록되고 Concurrent.broadcast를 사용하여 클라이언트에 브로드 캐스팅되는 다른 예입니다.
import play.api.mvc._
import play.api.libs.iteratee._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def socket = WebSocket.using[String] { request =>
// Concurrent.broadcast returns (Enumerator, Concurrent.Channel)
val (out, channel) = Concurrent.broadcast[String]
// log the message to stdout and send response back to client
val in = Iteratee.foreach[String] {
msg =>
println(msg)
// the Enumerator returned by Concurrent.broadcast subscribes to the channel and will
// receive the pushed messages
channel push("I received your message: " + msg)
}
(in,out)
}
'PlayFramework2' 카테고리의 다른 글
[Play2] Iteratee & Enumerators 간단 정리 (0) | 2017.02.18 |
---|---|
[Play2] ScalaAsync (번역) (0) | 2016.10.14 |
[Play2] 외부의 원격액터와 통신 (0) | 2016.10.11 |
[Play2] WS API (번역) (0) | 2016.10.11 |
[Play2] 마이크로서비스 (microservices) (0) | 2016.10.11 |