sta / websocket-sharp

A C# implementation of the WebSocket protocol client and server
http://sta.github.io/websocket-sharp
MIT License
5.71k stars 1.66k forks source link

Running WebSocket Sharp in Windows Services #56

Open dazxa opened 10 years ago

dazxa commented 10 years ago

Hi there, I've created a application using web socket sharp. This works fine when running as a console app, however when deployed as a windows service (As Admin) it fails on send. Debugging info below. Any ideas why this is would be most welcomed. Many thanks Darryl

4/07/2014 3:14:46 p.m.|Debug|WebSocket.send:0|A WebSocket connection request to wss://url:443/websocket/v2: GET /websocket/v2 HTTP/1.1 User-Agent: websocket-sharp/1.0 Upgrade: websocket Connection: Upgrade Host: url:443 Sec-WebSocket-Key: pFtLpPPxJ5WBJ/G8BR5A+Q== Sec-WebSocket-Protocol: wss Sec-WebSocket-Version: 13 4/07/2014 3:14:46 p.m.|Debug|WebSocket.receiveHandshakeResponse:0|A response to this WebSocket connection request: HTTP/1.1 101 Switching Protocols Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Accept: kOyOtZ3xHDrgox+kybKdkG3wMZA= Sec-WebSocket-Protocol: wss 4/07/2014 3:14:46 p.m.|Error|WebSocket.Send:0|While closing the WebSocket connection. 4/07/2014 3:14:46 p.m.|Info |WebSocket.close:0|Closing the WebSocket connection has already been done. 4/07/2014 3:14:46 p.m.|Debug|WebSocket.closeHandshake:0|Was clean?: True sent: True received: True

sta commented 10 years ago

Hello there,

Would you show me WebSocket part of your apps code? (The above logs seem like that a data was sent after the WebSocket closing.)

dazxa commented 10 years ago

Hi there,

Abridged code is below.

Many thanks

Darryl

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Configuration;
using WebSocketSharp;

namespace WebSocketProxyService
{
    public partial class WebSocketProxy : ServiceBase
    {
    public WebSocketProxy()
    {
        InitializeComponent();

        if (!System.Diagnostics.EventLog.SourceExists("WebSocketProxyService"))
        {
        System.Diagnostics.EventLog.CreateEventSource("WebSocketProxyService", "WebSocketProxyServiceLog");
        }
        eventLog1.Source = "WebSocketProxyService";
        eventLog1.Log = "WebSocketProxyServiceLog";
    }

    protected override void OnStart(string[] args)
    {
        eventLog1.WriteEntry("WebSocketProxyService On Start", EventLogEntryType.Information);

        MetServiceMessageHandler messageHandler = null;

        try
        {
        messageHandler = new MetServiceMessageHandler(eventLog1);
        }
        catch (Exception e1)
        {
        eventLog1.WriteEntry("Error: " + e1.Message, EventLogEntryType.Error);
        }

        string serviceWebSocketAddress = string.Empty;

        try
        {
        serviceWebSocketAddress = ConfigurationManager.AppSettings["ServiceWebSocketAddress"];
        }

        catch (Exception e2)
        {
        eventLog1.WriteEntry("Error: " + e2.Message, EventLogEntryType.Error);
        }

        try
        {
        eventLog1.WriteEntry(serviceWebSocketAddress);

        using(var ws = new WebSocket(serviceWebSocketAddress))
        {

            ws.Log.File = "C:/logs/log.txt";
            ws.Log.Level = LogLevel.Debug;

            eventLog1.WriteEntry("Log Level:" + ws.Log.Level);
            eventLog1.WriteEntry("File:"  + ws.Log.File);

            ws.OnOpen += (sender, e) =>
            {
            eventLog1.WriteEntry("Opened New Connection");
            };

            ws.OnClose += (sender, e) =>
            {
            eventLog1.WriteEntry(String.Format("Closed Connection, Code: {0} \n Reason: {1}: \n Raw: {2} Sender: {3}", e.Code, e.Reason, e.ToString(), sender.ToString()));
            };

            ws.OnMessage += (sender, e) =>
            {
            eventLog1.WriteEntry("Message");
            messageHandler.HandleMessage(e.Data, ws);
            };

            eventLog1.WriteEntry("Begin Connect");
            ws.Connect();
            eventLog1.WriteEntry("End Connect");

        }
        }

        catch (Exception ex)
        {
        eventLog1.WriteEntry(String.Format("Error Connection, Msg: {0} \n Inner Exception: {1}\n Stack Trace: {2}", ex.Message, ex.InnerException, ex.StackTrace), EventLogEntryType.Error);
        }

    }

    protected override void OnStop()
    {
        eventLog1.WriteEntry("WebSocketProxyService Entering On Stop");
    }

    private void eventLog1_EntryWritten(object sender, EntryWrittenEventArgs e)
    {

    }
    }
}

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using WebSocketProxyService.EsriData;
using WebSocketSharp;
using WebSocketSharp.Server;

namespace WebSocketProxyService
{
    public interface IMessageHandler
    {
    void HandleMessage(string data, WebSocket ws);
    }

    public class ServiceMessageHandler : IMessageHandler
    {
    private WebSocketServer wsss;

    private EventLog messageHandlerLogger;

    public ServiceMessageHandler(EventLog logger)
    {
        try
        {
        messageHandlerLogger = logger;
        string url = ConfigurationManager.AppSettings["WebSocketHostUrl"];
        wsss = new WebSocketServer(url);
        wsss.AddWebSocketService<Broadcaster>("/MyEndPoint");
        wsss.Start();
        }
        catch (Exception e)
        {
        logger.WriteEntry("Error: " + e.Message, EventLogEntryType.Error);
        }
    }

    public void HandleMessage(string data, WebSocketSharp.WebSocket ws)
    {
        try
        {
        JObject msg = JsonConvert.DeserializeObject(data) as JObject;

        this.messageHandlerLogger.WriteEntry("Msg Recieved:" + data, EventLogEntryType.Information);

        string msgType = msg.Value<String>("type");

        if (msgType == "401")
        {
            serviceAuthDoc ServiceAuthDoc = new ServiceAuthDoc();

            serviceAuthDoc.user = ConfigurationManager.AppSettings["ServiceAuthDocUser"];
            serviceAuthDoc.product = ConfigurationManager.AppSettings["ServiceAuthDocProduct"];

            Document document = new Document();

            long timeout;

            long.TryParse(ConfigurationManager.AppSettings["ServiceAuthDocTimeout"], out timeout);

            document.timeout = timeout;

            serviceAuthDoc.document = JsonConvert.SerializeObject(document);

            serviceAuthDoc.expiryDate = ConfigurationManager.AppSettings["ServiceAuthDocExpiryDate"];
            serviceAuthDoc.signature = ConfigurationManager.AppSettings["ServiceAuthDocSignature"];

            string authDoc = JsonConvert.SerializeObject(serviceAuthDoc);

            MyData myData = new MyData();
            myData.type = "auth";
            myData.data = authDoc;

            string returnMsg = JsonConvert.SerializeObject(metData);

            this.messageHandlerLogger.WriteEntry("Pre Send With Msg:" + returnMsg, EventLogEntryType.Information);
            ws.Send(returnMsg);
        }
        else if (msgType == "auth")
        {
            this.messageHandlerLogger.WriteEntry("Auth: " + msg.Value<String>("data"), EventLogEntryType.Information);

        }
        else if (msgType == "servicemsg")
        {                                    
            this.messageHandlerLogger.WriteEntry("Service msg: " + msg.Value<String>("data"), EventLogEntryType.Information);
            wsss.WebSocketServices.Broadcast(msg.ToString());
        }
        else if (msgType == "status")
        {
               this.messageHandlerLogger.WriteEntry("Status msg: " + msg.Value<String>("data"), EventLogEntryType.Information);
        }

        else if (msgType == "error")
        {
            this.messageHandlerLogger.WriteEntry("Error: " + msg.Value<String>("data"), EventLogEntryType.Error);
        }
        else
        {
            this.messageHandlerLogger.WriteEntry("Error: " + msg.Value<String>("data"), EventLogEntryType.Error);
        }

        }
        catch (Exception e)
        {
        this.messageHandlerLogger.WriteEntry("Error: " + e.Message, EventLogEntryType.Error);
        }
    }

    }

    public class Broadcaster : WebSocketService
    {
    public EventLog messageHandlerLogger;

    protected override void OnOpen()
    {
        base.OnOpen();
    }

    protected override void OnClose(CloseEventArgs e)
    {
        base.OnClose(e);
    }

    protected override void OnError(WebSocketSharp.ErrorEventArgs e)
    {
        base.OnError(e);
    }

    protected override void OnMessage(MessageEventArgs e)
    {

    }
    }
}
dazxa commented 10 years ago

Hi there,

As I was using a "using" statement above, the services container was calling Dispose as this implements iDisposable. See above code.

As a fix I am going to remove the using statement to allow the web socket to be deployed using windows services.

Any comments or suggestions welcomed.

Best Regards

Darryl

sta commented 10 years ago

@dazxa Thanks for input.

namespace WebSocketProxyService
{
    public partial class WebSocketProxy : ServiceBase
    {
        ...

        private WebSocket ws;

        protected override void OnStart(string[] args)
        {
            ...
            try
            {
                // Remove using statement.
                ws = new WebSocket(serviceWebSocketAddress);
                ...
                ws.Connect();
                eventLog1.WriteEntry("End Connect");
            }
            catch (Exception ex)
            {
                ...
            }
        }

        protected override void OnStop()
        {
            eventLog1.WriteEntry("WebSocketProxyService Entering On Stop");
            if (ws != null && ws.ReadyState == WebSocketState.Open)
              ws.Close();
        }

        ...
    }
}

I think you should remove using statement, too.

So, have you still got same error?

dazxa commented 10 years ago

Hi there,

Removing the "using" statement fixes the issue.

I will call dispose() explicitly on stop.

Many thanks

Darryl