ãã®ãœãªã¥ãŒã·ã§ã³ã®ã¢ã€ãã¢ã¯ãWebãã£ãããäœæããããã®Perlã§ã®Cometãã¯ãããžãŒã®å®è£ ã«ã€ããŠèª¬æããHabréã®èšäºãžã®ãªã³ã¯ãå ±æããååããæããããªãæãã€ãããã®ã§ãã ã åœæã¯ããªããå¿ èŠãšãããã®ã§ãïŒ ããšç§ãã¡ã¯èããç§ã¯ãã®ããšãASP.NETã«ãã蟌ãæ¹æ³ãèŠã€ãå§ããŸããã å®éã«ã¯ãã«ããã®äžã§äœãè°è«ãããŸããã
ãŸããCometãšã¯äœããèããŸãããã ãŠã£ãããã£ã¢ãããã«ã€ããŠç§ãã¡ã«äŒããŠããããšã¯æ¬¡ã®ãšããã§ãã
Comet ïŒWebéçºïŒã¯ãWebã¢ããªã±ãŒã·ã§ã³ã®ã¢ãã«ã説æããæ°èªã§ããHTTPæ¥ç¶ã䜿çšãããšãWebãµãŒããŒã¯ããã©ãŠã¶ãŒããã®è¿œå èŠæ±ãªãã«ãã©ãŠã¶ãŒã«ããŒã¿ãããã·ã¥ã§ããŸãã ã³ã¡ããã¯ããã®çžäºäœçšãéæããããã®ããŸããŸãªææ³ã瀺ãããã«äœ¿çšããããã€ããŒããŒã ã§ãã ãããã®ã¡ãœããã®å ±éç¹ã¯ãç¬èªã®ãã©ã°ã€ã³ã§ã¯ãªããJavaScriptãªã©ã®ãã©ãŠã¶ãŒã§çŽæ¥ãµããŒããããŠãããã¯ãããžãŒã«åºã¥ããŠããããšã§ãã çè«çã«ã¯ãCometã®ã¢ãããŒãã¯ããã©ãŠã¶ãããŒãžãæŽæ°ããããã«ããŒãžå šäœãŸãã¯äžéšãèŠæ±ããWorld Wide Webã®å ã®æŠå¿µãšã¯ç°ãªããŸãã ãã ããå®éã«ã¯ãCometã¢ããªã±ãŒã·ã§ã³ã¯éåžžãé·ãããŒãªã³ã°ã§Ajaxã䜿çšããŠãµãŒããŒäžã®æ°ããæ å ±ã確èªããŸãã
ã§ãããããã®å®çŸ©ããç§ãã¡ããšããããŒã¯ãŒãã¯ãAjax with long pollingãã§ãã ããã¯äœã§ãäœãšäžç·ã«é£ã¹ãããŸããïŒ ããã³ã°ããŒãªã³ã°ããã¯ãããžãŒã䜿çšããå Žåãã¯ã©ã€ã¢ã³ãã¯ãµãŒããŒã«ãªã¯ãšã¹ããéä¿¡ãã...åŸ æ©ããŸãã ãµãŒããŒã«æ°ããããŒã¿ã衚瀺ãããã®ãåŸ ã¡ãŸãã ããŒã¿ãå°çãããšããµãŒããŒã¯ãã®ããŒã¿ãã¯ã©ã€ã¢ã³ãã«éä¿¡ãããã®åŸãæ°ãããªã¯ãšã¹ããéä¿¡ããŠåã³åŸ æ©ããŸãã ããšã³ãã¬ã¹ãªã¯ãšã¹ããã®ä»£æ¿æè¡ãããšãã°ããããã ãForever iframeãïŒ ããã§ããå°ãèªãããšãã§ããŸã ïŒã¯ãåžžã«é©çšã§ãããã®ãšã¯ã»ã©é ãã§ãã ã¿ã€ã ã¢ãŠããªã©ããããŸã§èª°ããã£ã³ã»ã«ããŠããŸããã
ãŸããã¿ã¹ã¯ã¯éåžžã«æ確ã§ã-å©çšå¯èœãªããŒã«ïŒAJAX + ASP.NETïŒã§äžèšã®é·ãããŒãªã³ã°ãå®è£ ããå¿ èŠããããŸãã ããã¯æåã®åé¡ã«ã€ãªãããŸããã€ãŸãããµãŒããŒã«é¡§å®¢ã«éä¿¡ã§ããæ°ããããŒã¿ããããŸã§ïŒãããŠæããã«è€æ°ã®ã¯ã©ã€ã¢ã³ãããããŸã§ïŒãçä¿¡èŠæ±ãä¿åããå¿çãæäŸããªãæ¹æ³ã§ãã ãããŠãããã§éåæHTTPãã³ãã©ãŒãå©ãã«ãªããŸãã
public interface IHttpAsyncHandler : IHttpHandler
{
IAsyncResult BeginProcessRequest( HttpContext ctx,
AsyncCallback cb,
object obj);
void EndProcessRequest(IAsyncResult ar);
}
* This source code was highlighted with Source Code Highlighter .
IHttpHandlerã€ã³ã¿ãŒãã§ã€ã¹ããã§ã¯ãªããIHttpAsyncHandlerããã¯ã©ã¹ãç¶æ¿ããŸããIHttpAsyncHandlerã¯ã䜿ãæ £ããProcessRequestã¡ãœãããšå ±ã«BeginProcessRequestãšEndProcessRequestã®2ã€ã®æ°ããã¡ãœãããæäŸããŸãã ç¹ã«ãæåã®ãã®ã«èå³ããããŸãããªããªãã ã€ãŸãããªã¯ãšã¹ãã®åŠçã®éå§æã«ããã®ãªã¯ãšã¹ããæã§ååŸããå¿ èŠããããXãæ¥ããŸã§æŸããªãã§ãã ããã ã芧ã®ãšãããBeginProcessRequestã¯IAsyncResultã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ãããªããžã§ã¯ããè¿ããŸãã
public interface IAsyncResult
{
public object AsyncState { get ; }
public bool CompletedSynchronously { get ; }
public bool IsCompleted { get ; }
public WaitHandle AsyncWaitHandle { get ; }
}
* This source code was highlighted with Source Code Highlighter .
æå®ãããã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããæ°ããã¯ã©ã¹ãäœæããBeginProcessRequestã«éä¿¡ãããèŠæ±ããŒã¿ãšç¬èªã®clientGuidãã©ã¡ãŒã¿ãŒã®ãªããžããªãšããŠãæ©èœããŸããããã¯ããµãŒããŒã«æ¥ç¶ããã¯ã©ã€ã¢ã³ãã®äžæã®èå¥åãšããŠå°æ¥äœ¿çšããäœããã®æ¹æ³ã§èŠæ±ãèå¥ããŸãã
public class CometAsyncRequestState : IAsyncResult
{
private HttpContext _currentContext;
private AsyncCallback _asyncCallback;
private Object _extraData;
private Boolean _isCompleted;
private Guid _clientGuid;
private ManualResetEvent _callCompleteEvent = null ;
public CometAsyncRequestState( HttpContext currentContext, AsyncCallback asyncCallback, Object extraData)
{
_currentContext = currentContext;
_asyncCallback = asyncCallback;
_extraData = extraData;
_isCompleted = false ;
}
public void CompleteRequest()
{
_isCompleted = true ;
lock ( this )
{
if (_callCompleteEvent != null )
_callCompleteEvent.Set();
}
if (_asyncCallback != null )
{
_asyncCallback( this );
}
}
public HttpContext CurrentContext
{
get
{
return _currentContext;
}
set
{
_currentContext = value ;
}
}
public AsyncCallback AsyncCallback
{
get
{
return _asyncCallback;
}
set
{
_asyncCallback = value ;
}
}
public Object ExtraData
{
get
{
return _extraData;
}
set
{
_extraData = value ;
}
}
public Guid ClientGuid
{
get
{
return _clientGuid;
}
set
{
_clientGuid = value ;
}
}
// IAsyncResult implementations
public Boolean CompletedSynchronously
{
get
{
return false ;
}
}
public Boolean IsCompleted
{
get
{
return _isCompleted;
}
}
public Object AsyncState
{
get
{
return _extraData;
}
}
public WaitHandle AsyncWaitHandle
{
get
{
lock ( this )
{
if (_callCompleteEvent == null )
_callCompleteEvent = new ManualResetEvent( false );
return _callCompleteEvent;
}
}
}
}
* This source code was highlighted with Source Code Highlighter .
ã芧ã®ãšãããCompleteRequesté¢æ°ãåŒã³åºããŸã§ããªã¯ãšã¹ãã¯å®äºãããšèŠãªãããŸããã çŽ æŽããã-ãããå¿ èŠã§ãã ãããã®çä¿¡ãªã¯ãšã¹ããä¿åããå Žæã¯ã©ããã«ã®ã¿æ®ã£ãŠããŸãã ãã®é¢æ°ããã³ãªã¯ãšã¹ãåŠçé¢æ°ã«å¯ŸããŠãéçã¯ã©ã¹CometClientProcessorãäœæããŸãã
public static class CometClientProcessor
{
private static Object _lockObj;
private static List <CometAsyncRequestState> _clientStateList;
static CometClientProcessor()
{
_lockObj = new Object();
_clientStateList = new List <CometAsyncRequestState>();
}
public static void PushData( String pushedData)
{
List <CometAsyncRequestState> currentStateList = new List <CometAsyncRequestState>();
lock (_lockObj)
{
foreach (CometAsyncRequestState clientState in _clientStateList)
{
currentStateList.Add(clientState);
}
}
foreach (CometAsyncRequestState clientState in currentStateList)
{
if (clientState.CurrentContext.Session != null )
{
clientState.CurrentContext.Response.Write(pushedData);
clientState.CompleteRequest();
}
}
}
public static void AddClient(CometAsyncRequestState state)
{
Guid newGuid;
lock (_lockObj)
{
while ( true )
{
newGuid = Guid .NewGuid();
if (_clientStateList.Find(s => s.ClientGuid == newGuid) == null )
{
state.ClientGuid = newGuid;
break ;
}
}
_clientStateList.Add(state);
}
}
public static void UpdateClient(CometAsyncRequestState state, String clientGuidKey)
{
Guid clientGuid = new Guid (clientGuidKey);
lock (_lockObj)
{
CometAsyncRequestState foundState = _clientStateList.Find(s => s.ClientGuid == clientGuid);
if (foundState != null )
{
foundState.CurrentContext = state.CurrentContext;
foundState.ExtraData = state.ExtraData;
foundState.AsyncCallback = state.AsyncCallback;
}
}
}
public static void RemoveClient(CometAsyncRequestState state)
{
lock (_lockObj)
{
_clientStateList.Remove(state);
}
}
}
* This source code was highlighted with Source Code Highlighter .
CometClientProcessorã«ã¯ãçŸåšä¿æãããŠãããªã¯ãšã¹ãã®ãªã¹ãããªã¯ãšã¹ããè¿œå ããããã®AddClienté¢æ°ïŒæ°ããã¯ã©ã€ã¢ã³ããæ¥ç¶ããå ŽåïŒããªã¯ãšã¹ããæŽæ°ããããã®UpdateClientïŒæ¢ã«æ¥ç¶ãããŠããã¯ã©ã€ã¢ã³ããæ°ãããªã¯ãšã¹ããéä¿¡ããå ŽåïŒãããã³ãªã¯ãšã¹ããåé€ããããã®RemoveClientïŒã¯ã©ã€ã¢ã³ããåæããå ŽåïŒãã¡ã€ã³PushDataã¡ãœããã ããããããããããã«ãæãåçŽãªããŒã¿ãã€ãŸãURLã®ãã©ã¡ãŒã¿ãŒãä»ããŠãµãŒããŒã«éãããè¡ããããã·ã¥ãããŸãã ã芧ã®ãšããããã¹ãŠãéåžžã«åçŽã§ããçŸåšä¿æãããŠããèŠæ±ãå®è¡ãããµãŒããŒããã®ããŒã¿ãå¿çã«æžã蟌ã¿ãCompleteRequesté¢æ°ãåŒã³åºããŠãèŠæ±ã解æŸããã¯ã©ã€ã¢ã³ãã«å¿çãéä¿¡ããŸãã ãã®äŸã§ã¯ãå¯äžã®ããŒãžã®Page_Loadé¢æ°ããPushDataåŒã³åºããè¡ãããŸãã
protected void Page_Load( object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Request.QueryString[ "x" ] != null )
{
CometClientProcessor.PushData(Request.QueryString[ "x" ].ToString());
}
}
}
* This source code was highlighted with Source Code Highlighter .
åè¿°ã®ããã«ãããŒã¿ã¯URLã®ãã©ã¡ãŒã¿ãŒãä»ããŠååŸãããŸãããã®å Žåãããããããããããã«ãxããšåŒã°ããŸãã ãµãŒããŒéšåã§ã¯ãå®éã«ã¯éåæãã³ãã©ãŒèªäœãå®è£ ããã ãã§ãã ããããæåã«ãã¯ã©ã€ã¢ã³ãéšåã«ç®ãåããŠïŒjQueryã©ã€ãã©ãªãŒã®å©ããªãã§ã¯ãªãïŒããã€ãã®ããªãæ®éã®JavaScripté¢æ°ãäœæããŸãããã
var clientGuid
$( document ).ready( function () {
var str = window.location.href;
if (str.indexOf( "?" ) < 0)
Connect();
});
$(window).unload( function () {
var str = window.location.href;
if (str.indexOf( "?" ) < 0)
Disconnect();
});
function SendRequest() {
var url = './CometAsyncHandler.ashx?cid=' + clientGuid;
$.ajax({
type: "POST" ,
url: url,
success: ProcessResponse,
error: SendRequest
});
}
function Connect() {
var url = './CometAsyncHandler.ashx?cpsp=CONNECT' ;
$.ajax({
type: "POST" ,
url: url,
success: OnConnected,
error: ConnectionRefused
});
}
function Disconnect() {
var url = './CometAsyncHandler.ashx?cpsp=DISCONNECT' ;
$.ajax({
type: "POST" ,
url: url
});
}
function ProcessResponse(transport) {
$( "#contentWrapper" ).html(transport);
SendRequest();
}
function OnConnected(transport) {
clientGuid = transport;
SendRequest();
}
function ConnectionRefused() {
$( "#contentWrapper" ).html( "Unable to connect to Comet server. Reconnecting in 5 seconds..." );
setTimeout(Connect(), 5000);
}
* This source code was highlighted with Source Code Highlighter .
ããã¥ã¡ã³ããèªã¿èŸŒãŸãããšããã«ãURLã§ãã©ã¡ãŒã¿ãŒã®ååšã確èªãïŒãã©ã¡ãŒã¿ãŒåãããURLãããäžåºŠãç¥ããããŸã-ããã¯ããã·ã¥ã®ããã«ãµãŒããŒã«ããŒã¿ãéä¿¡ããŠããŸãïŒãConnecté¢æ°ãåŒã³åºããŸãã ããã¯ãé çªã«ããã§ã«ãã³ãã©ãŒãšã®éä¿¡ãéå§ããŠããŸãã ããããããããã«ãã¢ã¯ã·ã§ã³ãå®çŸ©ãããµãŒãã¹ã¯ãŒãïŒCONNECT / DISCONNECTïŒã¯ãcpspãã©ã¡ãŒã¿ãŒãä»ããŠæž¡ãããŸãã ãããã£ãŠãConnectã¯ãµãŒããŒã§AddClientåŒã³åºããéå§ããDisconnect-RemoveClientãéå§ããå¿ èŠããããŸãã æ¥ç¶ã確ç«ãããã¯ã©ã€ã¢ã³ããclientGuidãåä¿¡ãããšãSendRequesté¢æ°ãåŒã³åºãããŸããããã¯ãã¯ã©ã€ã¢ã³ããæ¥ç¶ãåæããããšã決å®ãããŸã§ãµãŒããŒãããã³ã°ãã£ã«ãããŸãã åSendRequeståŒã³åºãã¯ããµãŒããŒäžã§UpdateClienté¢æ°ã®å®è¡ãéå§ãããã®ã¯ã©ã€ã¢ã³ãã¯ã³ã³ããã¹ããšã³ãŒã«ããã¯ãæŽæ°ããŸãã
ããŠãã»ãšãã©ãã¹ãŠã®æºåãæŽã£ãã®ã§ãäžèšã®ã¡ã«ããºã å šäœã®äžæ žã§ããéåæãã³ãã©ãŒãå®è£ ãããšããæ¥ãŸããã
public enum ConnectionCommand
{
CONNECT,
DISCONNECT
}
public static class ConnectionProtocol
{
public static String PROTOCOL_GET_PARAMETER_NAME = "cpsp" ;
public static String CLIENT_GUID_PARAMETER_NAME = "cid" ;
}
* This source code was highlighted with Source Code Highlighter .
<%@ WebHandler Language= "C#" Class= "CometAsyncHandler" %>
using System;
using System.Web;
using DevelopMentor;
public class CometAsyncHandler : IHttpAsyncHandler, System.Web.SessionState.IRequiresSessionState
{
static private ThreadPool _threadPool;
static CometAsyncHandler()
{
_threadPool = new ThreadPool(2, 50, "Comet Pool" );
_threadPool.PropogateCallContext = true ;
_threadPool.PropogateThreadPrincipal = true ;
_threadPool.PropogateHttpContext = true ;
_threadPool.Start();
}
public IAsyncResult BeginProcessRequest( HttpContext ctx, AsyncCallback cb, Object obj)
{
CometAsyncRequestState currentAsyncRequestState = new CometAsyncRequestState(ctx, cb, obj);
_threadPool.PostRequest( new WorkRequestDelegate(ProcessServiceRequest), currentAsyncRequestState);
return currentAsyncRequestState;
}
private void ProcessServiceRequest(Object state, DateTime requestTime)
{
CometAsyncRequestState currentAsyncRequestState = state as CometAsyncRequestState;
if (currentAsyncRequestState.CurrentContext.Request.QueryString[ConnectionProtocol.PROTOCOL_GET_PARAMETER_NAME] ==
ConnectionCommand.CONNECT.ToString())
{
CometClientProcessor.AddClient(currentAsyncRequestState);
currentAsyncRequestState.CurrentContext.Response.Write(currentAsyncRequestState.ClientGuid.ToString());
currentAsyncRequestState.CompleteRequest();
}
else if (currentAsyncRequestState.CurrentContext.Request.QueryString[ConnectionProtocol.PROTOCOL_GET_PARAMETER_NAME] ==
ConnectionCommand.DISCONNECT.ToString())
{
CometClientProcessor.RemoveClient(currentAsyncRequestState);
currentAsyncRequestState.CompleteRequest();
}
else
{
if (currentAsyncRequestState.CurrentContext.Request.QueryString[ConnectionProtocol.CLIENT_GUID_PARAMETER_NAME] != null )
{
CometClientProcessor.UpdateClient(currentAsyncRequestState,
currentAsyncRequestState.CurrentContext.Request.QueryString[ConnectionProtocol.CLIENT_GUID_PARAMETER_NAME].ToString());
}
}
}
public void EndProcessRequest(IAsyncResult ar)
{
}
public void ProcessRequest( HttpContext context)
{
}
public bool IsReusable
{
get
{
return true ;
}
}
}
* This source code was highlighted with Source Code Highlighter .
äžèšã®ãã¹ãŠã®åŸã泚ææ·±ãèªè ãæã€ãããããªãå¯äžã®è³ªåã¯ããã«ã¹ã¿ã ã¹ã¬ããããŒã«ã䜿çšããçç±ãã§ãã å®å šã«æããã§ã¯ãããŸããããçãã¯éåžžã«åçŽã§ããASP.NETãã¬ããããŒã«ã®ã¯ãŒã¯ãããŒãã§ããã ãæ©ãã解æŸãããŠãçä¿¡èŠæ±ã®åŠçãç¶ç¶ããèŠæ±ã®çŽæ¥åŠçããå éšãã¹ã¬ããã«è»¢éã§ããããã«ããããã§ãã ãããè¡ãããªãå Žåãååãªæ°ã®çä¿¡èŠæ±ããããšãäžèŠãããšããäžèŠéŠ¬é¹¿ãããã®ã£ã°ããçºçããå¯èœæ§ããããŸãããASP.NETã¯ã¯ãŒã¯ãããŒã䜿ãæãããŸãããã åãçç±ã§ãBeginInvokeã¡ãœãããŸãã¯æšæºã®ã¹ã¬ããããŒã«ã¡ãœããThreadPool.QueueUserWorkItemã«ãã£ãŠå±èµ·ãããéåæããªã²ãŒãã䜿çšããããšã¯ã§ããŸããã ã©ã¡ãã®å Žåããã¹ã¬ããã¯åãASP.NETãã¬ãããã«ããåé€ããããç³é¹žã§çž«ãä»ãããããç¶æ³ã«ãªããŸãã ãã®äŸã§ã¯ãMike Woodringã«ãã£ãŠå®è£ ãããã«ã¹ã¿ã ã¹ã¬ããããŒã«ã䜿çšãããŸãã ãããšåœŒã®ä»ã®å€ãã®çºå±ã¯ããã§èŠãããŸã ã
åºæ¬çã«ã¯ä»¥äžã§ãã åœåã®ããã«é£ããã¯ãããŸããã§ããã ã¯ã©ã€ã¢ã³ãã¯Default.aspxãåŒã³åºããŠCometãµãŒããŒã«æ¥ç¶ããGETãã©ã¡ãŒã¿ãŒala Default.aspxïŒX = Happy_New_YearãåãããŒãžã«æž¡ãããšã§ããŒã¿ãããã·ã¥ããŸãã æ®å¿µãªããããã®ã¢ãããŒãã®ã¹ã±ãŒã©ããªãã£ã®å€§èŠæš¡ãªãã¹ãã¯ãŸã å¯èœã§ã¯ãããŸããããã ãããããã«ã€ããŠã¢ã€ãã¢ãæã£ãŠãããªããæžããŠãæ¥ããããããªãã§ãã ããã
ãæž èŽããããšãããããŸããã
UPD ãµã³ãã«ãããžã§ã¯ãã®ãªã³ã¯ãã¢ãŒã«ã€ãã«è¿œå ããŸã ïŒã30 KBïŒã 衚瀺æ¹æ³ïŒVSã§ã¯ãCometPage.aspxãã¹ã¿ãŒãããŒãžãšããŠèšå®ããèµ·åãããã©ãŠã¶ãŒ/ãã©ãŠã¶ãŒã§åãURLã§è€æ°ã®ã¿ããéãïŒãããã®ãã©ãŠã¶ãŒã§ã®åææ¥ç¶æ°ã®å¶éãèŠããŠããã ãã§ã ïŒããã©ã¡ãŒã¿ãŒãè¿œå ããŸããïŒX = [any_text]ãéããéããŠãããã¹ãŠã®ã¿ãã§ãã©ã¡ãŒã¿ãŒã®å€ãã©ã®ããã«è¡šç€ºããããã確èªããŸãã