statianzo / Fleck

C# Websocket Implementation
MIT License
2.29k stars 583 forks source link

System.Net.Sockets.SocketException: Address already in use #245

Open harrystuart opened 6 years ago

harrystuart commented 6 years ago

I am getting the error System.Net.Sockets.SocketException: Address already in use on the line server.Start(socket =>.... My server accepts a websocket request from the client, and works perfectly when a single connection is established. However, when the client attempts to make a concurrent websocket connection, the error occurs. What could be causing this errror? Client side or server side? Thanks, the code below is what I am using.

ConcurrentDictionary<Guid, IWebSocketConnection> allClientConnections = new ConcurrentDictionary<Guid, IWebSocketConnection>();
WebSocketServer server = new WebSocketServer("ws://0.0.0.0:2001");
        server.Start(socket =>
        {
            socket.OnOpen = () =>
            {

            };

            socket.OnMessage = message =>
            {

            };

            socket.OnClose = () =>
            {
                allClientConnections.TryRemove(socket.ConnectionInfo.Id, out IWebSocketConnection removedSocket);
            };

            socket.OnError = exception =>
            {
            };
        });`
AdrianBathurst commented 6 years ago

Again, this sounds like you are triggering the socket server to start up each time a client connects. If the socket server has started and is listening on your port 2001, you cannot start the socket server again. If you do, it will throw that error, because the port is already in use. You can only start the socket server again IF the app has stopped running and the socket server has released the port.

Put a debug breakpoint on the line WebSocketServer server = new WebSocketServer("ws://0.0.0.0:2001"); and see if the breakpoint is triggered each time a client connects. It should only be triggered once...and once only for the entire duration that the app is running.

harrystuart commented 6 years ago

I implemented some better debugging capability into my program, and it turns out that the actual error message is this:

System.Net.Sockets.SocketException: Address already in use at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName) at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.Sockets.Socket.Bind(EndPoint localEP) at Fleck.WebSocketServer.Start(Action'1 config) at telebot_pianomoves_v1.Program.Main(String[] args) in C:\Users\hjstu\Desktop\Telebot\Visual_Studio\my-project\Program.cs:line 227.

Noting that the error is actually occuring on line 277. This line is where I execute socket.Send(someBinary);. And the error only occured when two websocket requests were made near simultaneously. I doubt starting the websocket server is the problem now. Also, WebSocketServer server = new WebSocketServer("ws://0.0.0.0:2001"); is executed in public static void Main(string[] args) which is used as an entry point for the application and is not reinvoked.

Thanks

AdrianBathurst commented 6 years ago

Something is trying to bind to a port that's already in use, that's why the error is being thrown.

Maybe share a bit more logic from client & server side so we have more information to work with.

harrystuart commented 6 years ago

Here is a more detailed sample from my code. Essentially, the client sends an initial text message with some metadata, then I begin sending the binary audio data to a transcription service. When the transcription service detects that someone's speech has paused, it sends the transcription result. Once I receive this response, I repeat the process by beginning a new transcription service request and then send binary data to the service once again. The error I am receiving occurs most commonly before the first transcription service response is received, but is random sometimes also. I seem to get the error message System.NullReferenceException: Object reference not set to an instance of an object. in conjunction with the address error message. Both error messages occur at the line socket.OnBinary = async (binaryData) => await APICall.WriteAsync(binaryData).

    public static void Main(string[] args)
    {
        ConcurrentDictionary<Guid, IWebSocketConnection> allClientConnections = new ConcurrentDictionary<Guid, IWebSocketConnection>();
        WebSocketServer server = new WebSocketServer("ws://0.0.0.0:2001");

        server.Start(socket =>
        {
            bool firstMessage = false;

            socket.OnOpen = () =>
            {
                allClientConnections.TryAdd(socket.ConnectionInfo.Id, socket);
            };

            //After the websocket has been opened, I receive the first message from the client, the first message from the client is always textual and contains metadata for the connection, all subsequent messages are binary
            socket.OnMessage = message =>
            {
                //I initialise a speech transcription API here
                APICall = new TranscriptionRequest();
                firstMessage = true;
            };

            socket.OnClose = () =>
            {
                allClientConnections.TryRemove(socket.ConnectionInfo.Id, out IWebSocketConnection removedSocket);
            };

            //When the first binary message is received, invoke OnBinaryLambda()
            socket.OnBinary = binary => OnBinaryLambda(socket);

            socket.OnError = exception =>
            {
                throw new Exception(exception.ToString());
            };
        });
    }

    public static async Task OnBinaryLambda(IWebSocketConnection socket)
    {
        //firstMessage == true on invocation of this method
        if (firstMessage == true)
        {
            //Prevent this block from looping
            firstMessage = false;

            APICall.begin();

            //This task runs asynchronously, waiting to receive the speech transcription results
            Task.Run(async () =>
            {
                if(APICall.response = true)
                {
                    //When the transcription service results have been received, immediately repeat this process by reinvoking OnBinaryLambda() so that a new transcription service api call is made 
                    socket.OnBinary = async (binaryData) => await OnBinaryLambda();
                    firstMessage = true;
                }
            });

            //Once the transcription API has been initialised and the async task that listens to the response stream has been started, begin sending audio data to the transcription service
            socket.OnBinary = async (binaryData) => await APICall.WriteAsync(binaryData) //Every time a binary message is received, send it to the transcription service
        }
    }
njbrown09 commented 4 years ago

Im Getting This Too

frankli0324 commented 4 years ago

https://github.com/dotnet/runtime/issues/23803

please, change this line from netcoreapp2.0 to netcoreapp2.1 or above https://github.com/statianzo/Fleck/blob/9683310579a5632aa3f8d3c9e0023674389b570d/src/Fleck/Fleck.csproj#L12

njbrown09 commented 4 years ago

Still does not work :(