Why the ReceiveAsync method of ClientWebSocket never receive close frame message?

aluzi liu 486 Reputation points
2024-01-10T06:50:31.7+00:00

I am using ClientWebSocket to build a websocket client, I use ReceiveAsync method to receive message from server:

//wsClient is ClientWebSocket object
                    while (wsClient.State == WebSocketState.Open|| wsClient.State == WebSocketState.CloseReceived)
                    {
                        var result = await wsClient.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                        if (result.MessageType == WebSocketMessageType.Text)
                        {
                            string m = Encoding.UTF8.GetString(buffer, 0, result.Count);
                        }
                        else if(result.MessageType == WebSocketMessageType.Close)
                        {
//never run to here
                            string m2 = Encoding.UTF8.GetString(buffer, 0, result.Count);
                            Debug.WriteLine($"received close frame, info:{m2}");
                        }
                    }

If server send me normal text message, then client can receive the message as expected.

But if server send me close frame message, the client will send back a close frame to server automatically, and then turn to "Closed" status, the code will never run to the "if(result.MessageType == WebSocketMessageType.Close)" section, why?

I need to receive the close frame message, beacuse the close frame contain additional information I need to checkout.

.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,088 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,273 questions
0 comments No comments
{count} votes

Accepted answer
  1. Jiale Xue - MSFT 48,861 Reputation points Microsoft Vendor
    2024-01-10T08:15:18.39+00:00

    Hi @aluzi liu , Welcome to Microsoft Q&A,

    In WebSocket communication, when WebSocket receives a close frame from the server, it should also respond to the close frame and close the connection. This behavior is specified by the WebSocket protocol. When you use ReceiveAsync in ClientWebSocket to read a message, it automatically handles the close frame and closes the connection if needed.

    In the code, the ReceiveAsync method returns a result with WebSocketMessageType.Close when a close frame is detected. However, the WebSocket status may have changed to "Closed" before the code inside the else if(result.MessageType == WebSocketMessageType.Close) block is executed. That's why you can't see the code inside that block being run.

    You can call the CloseAsync method at the appropriate place in your WebSocket client code. Typically, you call this method on the sender of the close frame when your application decides to close the connection.

    if(someCondition)
    {
         //Send a close frame and wait for the connection to close
          await wsClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
    }
    

    The complete sample code needs to be modified according to your own situation:

    using System;
    using System.Net.WebSockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    class Program
    {
         static async Task Main(string[] args)
         {
             Uri serverUri = new Uri("wss://example.com/socket"); // Replace with your WebSocket server address
             using (ClientWebSocket wsClient = new ClientWebSocket())
             {
                 try
                 {
                     await wsClient.ConnectAsync(serverUri, CancellationToken.None);
    
                     //Perform other operations after successful connection
    
                     byte[] buffer = new byte[1024];
                     while (wsClient.State == WebSocketState.Open || wsClient.State == WebSocketState.CloseReceived)
                     {
                         var result = await wsClient.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                         if (result.MessageType == WebSocketMessageType.Text)
                         {
                             string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
                             Console.WriteLine($"Received message: {message}");
                         }
                         else if (result.MessageType == WebSocketMessageType.Close)
                         {
                             //Display the details of the closed frame
                             WebSocketCloseStatus closeStatus = result.CloseStatus ?? WebSocketCloseStatus.Empty;
                             string closeDescription = result.CloseStatusDescription;
    
                             Console.WriteLine($"Received close frame. Status: {closeStatus}, Description: {closeDescription}");
    
                             // Close the connection under certain conditions (this is just an example)
                             if(someCondition)
                             {
                                 await wsClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
                                 break; //Exit the loop
                             }
                         }
                     }
                 }
                 catch (Exception ex)
                 {
                     Console.WriteLine($"WebSocket error: {ex.Message}");
                 }
                 finally
                 {
                     if (wsClient.State == WebSocketState.Open || wsClient.State == WebSocketState.CloseSent)
                     {
                         // If the connection is still open, close the connection on exit
                         await wsClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
                     }
                 }
             }
         }
    
         //Replace with actual conditions
         static bool someCondition = false;
    }
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.