diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4856c0f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +SocketIO/obj/* +*.suo +*j.user +SocketIO/bin/* +SocketIO.userprefs diff --git a/SocketIO.sln b/SocketIO.sln index a66be6a..d28d4a9 100644 --- a/SocketIO.sln +++ b/SocketIO.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketIO", "SocketIO\SocketIO.csproj", "{2F18D000-F801-40FC-8B29-CA112E33536D}" EndProject Global @@ -14,6 +14,9 @@ Global {2F18D000-F801-40FC-8B29-CA112E33536D}.Release|x86.ActiveCfg = Release|x86 {2F18D000-F801-40FC-8B29-CA112E33536D}.Release|x86.Build.0 = Release|x86 EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = SocketIO\SocketIO.csproj EndGlobalSection diff --git a/SocketIO.userprefs b/SocketIO.userprefs deleted file mode 100644 index 880e1d0..0000000 --- a/SocketIO.userprefs +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/SocketIO/SocketIO.csproj b/SocketIO/SocketIO.csproj index 2f50ed6..48fa76c 100644 --- a/SocketIO/SocketIO.csproj +++ b/SocketIO/SocketIO.csproj @@ -1,5 +1,5 @@ - - + + Debug x86 @@ -10,6 +10,26 @@ SocketIO SocketIO v3.5 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true true @@ -19,7 +39,7 @@ DEBUG; prompt 4 - x86 + AnyCPU false @@ -79,4 +99,16 @@ bin\Debug\SocketIO.dll + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + \ No newline at end of file diff --git a/SocketIO/bin/Debug/SocketIO.dll b/SocketIO/bin/Debug/SocketIO.dll deleted file mode 100644 index 99e7487..0000000 Binary files a/SocketIO/bin/Debug/SocketIO.dll and /dev/null differ diff --git a/SocketIO/bin/Debug/SocketIO.pdb b/SocketIO/bin/Debug/SocketIO.pdb deleted file mode 100644 index 6c12f63..0000000 Binary files a/SocketIO/bin/Debug/SocketIO.pdb and /dev/null differ diff --git a/SocketIO/socketio/Client.cs b/SocketIO/socketio/Client.cs index 7055c76..e77d286 100644 --- a/SocketIO/socketio/Client.cs +++ b/SocketIO/socketio/Client.cs @@ -59,11 +59,6 @@ public class Client : IDisposable, SocketIOClient.IClient public event EventHandler SocketConnectionClosed; public event EventHandler Error; - /// - /// ResetEvent for Outbound MessageQueue Empty Event - all pending messages have been sent - /// - public ManualResetEvent MessageQueueEmptyEvent = new ManualResetEvent(true); - /// /// Connection Open Event /// @@ -128,15 +123,22 @@ public Client(string url, WebSocketVersion socketVersion) this.registrationManager = new RegistrationManager(); this.outboundQueue = (new ConcurrentQueue()); - this.dequeuOutBoundMsgTask = new Thread(new ThreadStart(dequeuOutboundMessages)); - //this.dequeuOutBoundMsgTask = Task.Factory.StartNew(() => dequeuOutboundMessages(), TaskCreationOptions.LongRunning); - this.dequeuOutBoundMsgTask.Start(); } /// /// Initiate the connection with Socket.IO service /// public void Connect() + { + Connect(null, null); + } + + /// + /// Initiate the connection with Socket.IO service using provided handshake query string and headers + /// + /// + /// + public void Connect(string query, string[] headers) { lock (padLock) { @@ -145,7 +147,7 @@ public void Connect() try { this.ConnectionOpenEvent.Reset(); - this.HandShake = this.requestHandshake(uri);// perform an initial HTTP request as a new, non-handshaken connection + this.HandShake = this.requestHandshake(uri, query, headers);// perform an initial HTTP request as a new, non-handshaken connection if (this.HandShake == null || string.IsNullOrEmpty(this.HandShake.SID) || this.HandShake.HadError) { @@ -159,7 +161,8 @@ public void Connect() string.Format("{0}://{1}:{2}/socket.io/1/websocket/{3}", wsScheme, uri.Host, uri.Port, this.HandShake.SID), string.Empty, this.socketVersion); - this.wsClient.EnableAutoSendPing = true; // #4 tkiley: Websocket4net client library initiates a websocket heartbeat, causes delivery problems + //this.wsClient.EnableAutoSendPing = true; // #4 tkiley: Websocket4net client library initiates a websocket heartbeat, causes delivery problems + this.wsClient.EnableAutoSendPing = false; // ANF: socket.io has it's own heartbeat, this should be unnecessary this.wsClient.Opened += this.wsClient_OpenEvent; this.wsClient.MessageReceived += this.wsClient_MessageReceived; this.wsClient.Error += this.wsClient_Error; @@ -303,9 +306,11 @@ public void Emit(string eventName, Object payload) /// public void Send(IMessage msg) { - this.MessageQueueEmptyEvent.Reset(); if (this.outboundQueue != null) + { this.outboundQueue.Enqueue(msg.Encoded); + ThreadPool.QueueUserWorkItem(new WaitCallback(dequeueOutboundMessages)); + } } public void Send(string msg) { @@ -315,9 +320,11 @@ public void Send(string msg) { private void Send_backup(string rawEncodedMessageText) { - this.MessageQueueEmptyEvent.Reset(); if (this.outboundQueue != null) + { this.outboundQueue.Enqueue(rawEncodedMessageText); + ThreadPool.QueueUserWorkItem(new WaitCallback(dequeueOutboundMessages)); + } } /// @@ -404,7 +411,10 @@ protected void closeWebSocketClient() // websocket client events - open, messages, errors, closing private void wsClient_OpenEvent(object sender, EventArgs e) { - this.socketHeartBeatTimer = new Timer(OnHeartBeatTimerCallback, new object(), HandShake.HeartbeatInterval, HandShake.HeartbeatInterval); + // ANF: only enable the heartbeat timer if the interval is non-zero + if(HandShake.HeartbeatInterval.TotalMilliseconds!=(double)0.0) + this.socketHeartBeatTimer = new Timer(OnHeartBeatTimerCallback, new object(), HandShake.HeartbeatInterval, HandShake.HeartbeatInterval); + this.ConnectionOpenEvent.Set(); this.OnMessageEvent(new EventMessage() { Event = "open" }); @@ -413,6 +423,9 @@ private void wsClient_OpenEvent(object sender, EventArgs e) try { this.Opened(this, EventArgs.Empty); } catch (Exception ex) { Trace.WriteLine(ex); } } + + // send any messages we might have queued while opening the connection + ThreadPool.QueueUserWorkItem(new WaitCallback(dequeueOutboundMessages)); } @@ -547,34 +560,16 @@ private void EndAsyncEvent(IAsyncResult result) } } /// - /// While connection is open, dequeue and send messages to the socket server + /// dequeue and send messages to the socket server /// - protected void dequeuOutboundMessages() + protected void dequeueOutboundMessages(Object stateinfo) { - while (this.outboundQueue != null) + if (this.ReadyState == WebSocketState.Open && this.outboundQueue != null) { - if (this.ReadyState == WebSocketState.Open) - { - string msgString; - try - { - if (this.outboundQueue.TryDequeue(out msgString)) - { - this.wsClient.Send(msgString); - } - else - this.MessageQueueEmptyEvent.Set(); - } - catch(Exception ex) - { - Trace.WriteLine("The outboundQueue is no longer open..."); - } - } - else - { - this.ConnectionOpenEvent.WaitOne(2000); // wait for connection event - } - } + string msgString; + while(this.outboundQueue.TryDequeue(out msgString)) + this.wsClient.Send(msgString); + } } /// @@ -583,19 +578,24 @@ protected void dequeuOutboundMessages() /// The tansport and sid are required as part of the ws: transport connection /// /// http://localhost:3000 + /// nullable, optional query string + /// nullable, Optional headers(ex: "name:value") /// Handshake object with sid value /// DownloadString: 13052140081337757257:15:25:websocket,htmlfile,xhr-polling,jsonp-polling - protected SocketIOHandshake requestHandshake(Uri uri) + protected SocketIOHandshake requestHandshake(Uri uri, string query, string[] headers) { string value = string.Empty; string errorText = string.Empty; SocketIOHandshake handshake = null; using (WebClient client = new WebClient()) - { + { + if (headers != null && headers.Length > 0) + foreach (string s in headers) + client.Headers.Add(s); try { - value = client.DownloadString(string.Format("{0}://{1}:{2}/socket.io/1/{3}", uri.Scheme, uri.Host, uri.Port, uri.Query)); // #5 tkiley: The uri.Query is available in socket.io's handshakeData object during authorization + value = client.DownloadString(string.Format("{0}://{1}:{2}/socket.io/1/{3}", uri.Scheme, uri.Host, uri.Port, string.IsNullOrEmpty(query) ? uri.Query: query)); // #5 tkiley: The uri.Query is available in socket.io's handshakeData object during authorization // 13052140081337757257:15:25:websocket,htmlfile,xhr-polling,jsonp-polling if (string.IsNullOrEmpty(value)) errorText = "Did not receive handshake string from server"; @@ -630,7 +630,6 @@ protected virtual void Dispose(bool disposing) { // free managed resources this.Close(); - this.MessageQueueEmptyEvent.Close(); this.ConnectionOpenEvent.Close(); }