Java開発者向けのSIPプログラミング

Session Initiation Protocol(SIP)は、インターネット技術特別調査委員会(IETF)によって開発された制御(シグナリング)プロトコルであり、IPテレフォニー、プレゼンス、インスタントメッセージングなどのインタラクティブマルチメディアIPセッションを管理します。Java Community Processを通じて開発されたSIPサーブレット仕様(Java Specification Request 116)は、SIPベースのサービスを提供するための標準のJavaAPIプログラミングモデルを提供します。Java Platform Enterprise Edition(Java EEはSunのJ2EEの新しい名前)の一般的なJavaサーブレットアーキテクチャから派生したSIPサーブレットは、インターネットアプリケーション開発機能をSIPソリューションにもたらします。

ITとテレコムは収束しています。ネットワークITアプリケーション(通常はデータ指向)は、通信アプリケーションと統合されています。Webページに表示されるCallMeボタンの数の増加は、この統合の例です。SIPサーブレット仕様は、コンバージドアプリケーションを構築するための使い慣れたプログラミングモデルをJava開発者にもたらします。この記事では、SIPサーブレットを使用して簡単なエコーチャットサービスを構築する方法を段階的に紹介します。

セッション開始プロトコル

Request for Comments 3261で定義されているSIPは、マルチメディアIP通信セッションを確立、変更、および終了するためのプロトコルです。図1は、SIPを使用してVoIP(ボイスオーバーインターネットプロトコル)コールを確立する簡単な例です。

図1の白い線はすべて、SIP通信を表しています。発信者はSIPINVITE要求を送信して、「着信者」を招待して音声セッションを確立します。着信者は最初に、電話が鳴っていることを示す180のステータスコードを持つメッセージで応答します。電話が受信されるとすぐに、200のステータスコードを含む応答が発信者に送信され、招待を受け入れます。発信者はACKメッセージで確認し、セッションが確立されます。セッションが確立されると、実際のデジタル化された音声会話は、通常、図1の赤い線が示すように、セッションとともにRealtime Transmission Protocol(RTP)を介して送信されます。会話が終了すると、SIP BYE要求が送信され、続いてセッションの終了を確認するための200ステータスコードの応答が送信されます。

SIPINVITE要求と200OKステータスコードの応答の例を次に示します。

SIP INVITE request: INVITE sip:[email protected] SIP/2.0 Via: SIP/2.0/UDP pc.caller.com;branch=z9hG4bK776asdhds Max-Forwards: 70 To: Callee From: Caller ;tag=1928301774 Call-ID: a84b4c76e66710 CSeq: 314159 INVITE Contact: Content-Type: application/sdp Content-Length: 142

(content (SDP) is not shown)

SIP 200 OK応答:

SIP/2.0 200 OK Via: SIP/2.0/UDP pc.caller.com;branch=z9hG4bK776asdhds;received=192.0.2.1 To: Callee ;tag=a6c85cf From: Caller ;tag=1928301774 Call-ID: a84b4c76e66710 CSeq: 314159 INVITE Contact: Content-Type: application/sdp Content-Length: 131

(content (SDP) is not shown)

ご覧のとおり、SIPの形式はHTTPに似ています。ただし、HTTPと比較すると、SIPは次のとおりです。

  • セッション管理を担当します。インスタントメッセージ、音声、ビデオなどの実際のマルチメディアコンテンツは、SIPを介して送信される場合とされない場合があります。
  • 非同期でステートフル。SIP要求ごとに、複数の応答が存在する可能性があります。これは、アプリケーションが適切な状態コンテキスト内で各SIPメッセージを処理する必要があることを意味します。
  • 信頼できるトランスポートと信頼できないトランスポートの両方で実行できるアプリケーションプロトコル。したがって、アプリケーションは、メッセージの再送信と確認応答を使用してメッセージの配信を保証する必要があります。
  • クライアントとサーバーの間に明確な区別がないピアツーピアプロトコル。どちらの側も、要求と応答を送受信できる必要があります。

SIPベースのサービス

SIPベースのサービスは、メッセージルーティングなどのサービスをIP電話などのSIPエンドポイントに提供するSIPサーバーです。たとえば、図2では、SIPレジストラサーバーとプロキシサーバーがSIP登録とプロキシサービスを提供して、SIPエンドポイントが相互に検索して通信できるようにしています。

図2は、次のことを示しています。

  1. Calleeは、REGISTERリクエストを送信することにより、自分自身をレジストラサーバーに登録します。
  2. レジストラサーバーは、200 OKステータスコードで応答することにより、呼び出し先の名前アドレスを含む登録を受け入れます。
  3. 呼び出し元は、プロキシサーバーにINVITE要求を送信することにより、呼び出し先との通信セッションを確立するように要求します。INVITEメッセージのコンテンツには、通常、メディアタイプ、セキュリティ、IPアドレスなど、発信者が確立したい通信セッションの説明が含まれています。説明は通常、Session Description Protocol(SDP)形式です。
  4. プロキシサーバーは、レジストラサーバーを検索して、呼び出し先の現在のアドレスを見つけます。ルックアップはSIPの一部ではなく実装の問題であることに注意してください。
  5. プロキシサーバーは、現在のアドレスに基づいて、呼び出し元から呼び出し先にINVITE要求を転送します。
  6. 呼び出し先は、200 OKステータスコードで応答することにより、招待を受け入れます。INVITE要求に対する200OK応答には、通常、呼び出し先が呼び出し元と確立できる通信セッションの説明が含まれています。
  7. プロキシサーバーは、200OK応答を呼び出し先から呼び出し元に転送します。
  8. 呼び出し元は、プロキシサーバーにACKメッセージを送信して、セッションの確立を確認します。ACKメッセージには、セッションの最終合意が含まれる場合があります。
  9. 次に、プロキシサーバーはACKを呼び出し先に転送します。このようにして、プロキシサーバーを介してスリーウェイハンドシェイクが完了し、セッションが確立されます。
  10. これで、発信者と着信者の間の通信が行われます。通信に使用されるプロトコルは、SIPである場合とそうでない場合があります。たとえば、インスタントメッセージはSIPを介して送信できます。音声会話は通常、RTPを介して送信されます。
  11. これで、呼び出し先は会話を終了し、BYE要求を送信してセッションを終了したいと考えています。
  12. 発信者は、セッションの終了を受け入れるために200OKステータスコードで応答します。

上記のシナリオでは、SIPプロキシサーバーは単にメッセージを呼び出し先の現在のアドレスにルーティングします。ご想像のとおり、より興味深くスマートなルーティングサービスが発生する可能性があります。たとえば、プロキシサーバーは、誰かがオフィスの電話で電話をかけている場合でも、携帯電話などの到達可能な場所にメッセージをルーティングすることで「ユーザーをフォロー」できます。

SIPサーブレット

Java Specification Request 116で定義されているSIPサーブレット仕様は、SIPアプリケーションのコンテナサーブレットプログラミングモデルを提供します。JSR 116は、Java EEのJavaサーブレットアーキテクチャから派生しているため、JavaEE開発者にSIPサービスを構築するための使い慣れたアプローチをもたらします。

以下の表は、の間の類似性をまとめたものHTTPServletSIPServlet

HTTPサーブレットとSIPサーブレットの比較

  HTTP SIP
サーブレットクラス HttpServlet SipServlet
セッション HttpSession SipSession
アプリケーションパッケージ 戦争 SAR
Deployment descriptor web.xml sip.xml

Much like HTTP servlets, SIP servlets extend the javax.servlet.sip.SipServlet class, which in turn extends the javax.servlet.GenericServlet class. As you might have guessed, SipServlet overrides the service(ServletRequest request, ServletResponse response) method to handle different types of SIP messages.

Since SIP is asynchronous, only one of the request and response arguments in the service() method is valid; the other one is null. For example, if the incoming SIP message is a request, only the request is valid and the response is null, and vice versa. The default implementation of the SipServlet class dispatches requests to doXXX() methods and responses to doXXXResponse() methods with a single argument. For example, doInvite(SipServletRequest request) for a SIP invite request and doSuccessResponse(SipServletResponse response) for SIP 2xx class responses. Typically SIP servlets override doXXX() methods and/or doXXXResponse() methods to provide application logic.

How do you send SIP responses if there is no response object in the doXXX() methods? In SIP servlets, you must call one of the createResponse() methods in the javax.servlet.sip.SipServletRequest class to create a response object. Then, call the send() method on the response object to send the response.

How about creating a SIP request in a SIP servlet? There are two ways to create SIP requests: Call either one of the createRequest() methods on the SipSession class to create a SIP request within the session, or one of the createRequest() methods on javax.servlet.sip.SipFactory to create a SIP request within a new SipSession. To get an instance of SipFactory, you must call getAttribute("javax.servlet.sip.SipFactory") on the ServletContext class.

The SipFactory is a factory interface in the SIP Servlet API for creating various API abstractions, such as requests, address objects, and application sessions. One interesting object created by SipFactory is javax.servlet.sip.SipApplicationSession. The intention of JSR 116 is to create a unified servlet container that can run both an HTTP and a SIP servlet. SipApplicationSession provides a protocol-agnostic session object to store application data and correlate protocol-specific sessions, such as SipSession and HttpSession. Hopefully this concept will be adopted by future versions of the Servlet API to make it javax.servlet.ApplicationSession instead of javax.servlet.sip.SipApplicationSession.

The SipApplicationSession manages protocol-specific sessions like SipSession. The SipSession interface represents the point-to-point relationship between two SIP endpoints and roughly corresponds to a SIP dialog defined in Request for Comments 3261. SipSession is inherently more complicated than its HTTP counterpart due to SIP's asynchronous and unreliable nature mentioned above. For example, Figure 3 shows the SipSession state transitions defined in JSR 116:

Typically, an HttpSession is created when a user logs in and destroyed after logout. A SipSession typically represents one logical conversation, even if you have multiple conversations between the same endpoints. So SipSession is more dynamic and has a shorter lifespan.

SipSessionライフサイクルとSIPダイアログとの関係についてのより高度な説明は、この記事の範囲を超えています。幸い、コンテナはライフサイクルや状態遷移などの複雑さのほとんどを処理しSipSession、セッションデータのストレージとして簡単に使用できます。

完全な例:EchoServlet

EchoServletは、WindowsMessengerに入力したインスタントメッセージをエコーできるSIPサーブレットです。