Search code examples
c#socketsioerror

How to solve error : System.Net.Sockets.SocketException (995) when working with C# and socket


I am trying to set up a socket server with C#. Everything worked well until it suddenly showed the error : System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.

I have tried some solutions I found on stack overflow but it does not work. I have also tried disabling firewall on my machine and it still does not work. This error occurred suddenly and the error still shows when i reverted back to old versions that used to work.

Here is my server code using dotnet 6.0 :

using System;
using System.Text;
using System.Net.Sockets;
using System.IO;
using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Net.Http;
using System.Net;

namespace PokemonWebSocketServer
{
    internal class Server
    {
        public static List<Client>? clients = new();
        public static List<Room>? rooms = new();
        public static ClientRequest clientRequest;

        private static async Task Main(string[] args)
        {
            TcpListener listener = new TcpListener(System.Net.IPAddress.Any, 587);
            listener.Start();
            Console.WriteLine("Server has started !");
            Console.WriteLine("Waiting for clients to connect");

            while (true)
            {
                using (TcpClient tcpClient = await listener.AcceptTcpClientAsync())
                {
                    _ = HandleClientAsync(tcpClient);
                }
            }
        }

        private static async Task HandleClientAsync(TcpClient tcpClient)
        {
            using NetworkStream networkStream = tcpClient.GetStream();
            using StreamReader reader = new(networkStream);
            using StreamWriter writer = new(networkStream);
            try
            {
                byte[] buffer = new byte[15];
                int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);

                string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                clientRequest = Enum.Parse<ClientRequest>(receivedData);
                if (clientRequest == ClientRequest.Create)
                {
                    await CreateRoom(writer, networkStream, tcpClient);
                }
                else if (clientRequest == ClientRequest.Join)
                {
                    await JoinRoom(writer, networkStream, tcpClient);
                }
            }
            catch (System.IO.IOException e)
            {
                Console.WriteLine("Something went wrong !" + e);
            }
        }

The program will throw the error on the line :

int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);

This is my client code using dotnet 6.0 :

using System.Net.Sockets;
using System.Text;
using Newtonsoft.Json;

namespace PokemonGame
{
    internal class OnlinePokeBattle
    {
        public static byte[]? sendData;
        public static string? response;
        internal static void MakeConnection()
        {
            try
            {
                TcpClient client = new TcpClient("127.0.0.1", 587);
                StreamReader streamReader = new(client.GetStream());

                if(client.Connected)
                {
                    Console.Clear();
                    Console.WriteLine(AcsiiArt.MainMenuArt,"\n\n");
                    string prompt = "Would you like to join or create a room ?";
                    string[] options = {"Join", "Create", "Back"};
                    Console.WriteLine("\n\n\n");
                    Menu menu = new(prompt, options);
                    int MenuInput = menu.Run(false);

                    if(MenuInput == 0)
                    {
                        JoinRoom(client, streamReader);
                    }
                    else if(MenuInput == 1)
                    {
                        CreateRoom(client, streamReader);
                    }
                    if(MenuInput == 3)
                    {
                        Console.Clear();
                        return;
                    }
                }
                else
                {
                    Console.WriteLine("The server is currently not available.");
                    Thread.Sleep(2000);
                    return;
                }
            }
            catch(IOException e)
            {
                Console.WriteLine("The connection to server was lost ! \n" + e);
                return;
            }
            catch(Exception e)
            {
                Console.WriteLine("An error occured while trying to connect to the server !" + e);
                return;
            }
        }

This is the error :

!System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
 ---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.

The error occurs the moment the client connects to the server.

Please help me

The expected result is that the server waits for the client to send a string "Join" or "Create" and the program continues accordingly.


Solution

  • I have figured out the answer to the question. In summary, it was caused by this code in my server :

                while (true)
                {
                    using (TcpClient tcpClient = await listener.AcceptTcpClientAsync())
                    {
                        _ = HandleClientAsync(tcpClient);
                    }
                }
    

    Changing this code to this one worked :

                while (true)
                {
                    TcpClient tcpClient = await listener.AcceptTcpClientAsync();
                    _ = HandleClientAsync(tcpClient);
                }
    

    To further go into details, if anyone is interested, I will try my best to explain why the first one didn't work (please do keep in mind that I am a beginner programmer).

    What I was trying to achieve is to allow multiple clients to connect to my server concurrently. However, when my server code was using await such as

                while (true)
                {
                    TcpClient tcpClient = await listener.AcceptTcpClientAsync();
                    await HandleClientAsync(tcpClient);
                }
    

    What was happening was that the first client will be connected and the program continues for the first client ,however, for the second client, the program will pause until the first client finishes. So I knew I had to do something asynchronous, without the 'await'. So I changed my code to

                while (true)
                {
                    TcpClient tcpClient = await listener.AcceptTcpClientAsync();
                    _ = HandleClientAsync(tcpClient);
                }
    

    And this worked. 2 clients were able to connect concurrently. However, when I reviewed the code, I thought that using the 'using' keyword was beneficial as the 'using' keyword will release all the resources after the 'using' block has finished. After I changed my code to

                while (true)
                {
                    using (TcpClient tcpClient = await listener.AcceptTcpClientAsync())
                    {
                        _ = HandleClientAsync(tcpClient);
                    }
                }
    

    (I should have ran another test on my code and it was dumb of me not to) and I moved on and that was when the error occurred. I quickly reverted all my new changes until that 'using' keyword (because I thought it wouldn't be a problem).

    The problem was caused by 'using' keyword. After the 'using' statement, it moves onto another async function

    _ = HandleClientAsync(tcpClient);
    

    In this function, it has another async function

    'await networkStream.ReadAsync(buffer, 0, buffer.Length);'
    

    However, instead of the program waiting for the networkstream.ReadAsync, the async thread finishes and goes back to the while loop and therefore releasing the resources for the tcpClient. This is why it threw the error

    !System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
     ---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.
    

    But in this case, it was cause by the thread exit. When the networksteam was trying to read the data, there was no more tcpClient as the program has already released all the resources of the tcpClient.