如何解决使用 C# 和套接字时出现的错误:System.Net.Sockets.SocketException (995)

问题描述 投票:0回答:1

我正在尝试用 C# 设置套接字服务器。一切正常,直到突然显示错误:System.Net.Sockets.SocketException (995): I/O 操作已因线程退出或应用程序请求而中止。

我尝试了一些在堆栈溢出上找到的解决方案,但它不起作用。我也尝试在我的机器上禁用防火墙,但它仍然不起作用。这个错误突然发生,当我恢复到以前可以工作的旧版本时,该错误仍然显示。

这是我使用 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);
            }
        }

程序会抛出错误:

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

这是我使用 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;
            }
        }

这是错误:

!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.

客户端连接到服务器时就会出现错误。

请帮助我

预期的结果是服务器等待客户端发送字符串“Join”或“Create”,然后程序相应地继续。

c# sockets ioerror
1个回答
0
投票

我已经找到问题的答案了。总而言之,这是由我的服务器中的这段代码引起的:

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

将此代码更改为此代码有效:

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

为了进一步详细说明,如果有人感兴趣,我会尽力解释为什么第一个不起作用(请记住我是一名初学者程序员)。

我试图实现的是允许多个客户端同时连接到我的服务器。但是,当我的服务器代码使用等待时,例如

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

发生的情况是,第一个客户端将被连接,并且程序将继续第一个客户端,但是,对于第二个客户端,程序将暂停,直到第一个客户端完成。所以我知道我必须异步做一些事情,而不需要“等待”。所以我将代码更改为

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

这很有效。 2 个客户端能够同时连接。但是,当我查看代码时,我认为使用“using”关键字是有益的,因为“using”关键字将在“using”块完成后释放所有资源。当我将代码更改为

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

(我应该对我的代码进行另一次测试,但我很愚蠢没有这样做),然后我继续前进,那就是错误发生的时候。我很快恢复了所有新更改,直到使用“using”关键字(因为我认为这不会成为问题)。

问题是由“using”关键字引起的。在“using”语句之后,它转移到另一个异步函数

_ = HandleClientAsync(tcpClient);

在这个函数中,它还有另一个异步函数

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

但是,程序不是等待 networkstream.ReadAsync,而是异步线程完成并返回到 while 循环,从而释放 tcpClient 的资源。这就是它抛出错误的原因

!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.

但在这种情况下,这是由线程退出引起的。当networksteam尝试读取数据时,已经没有tcpClient了,因为程序已经释放了tcpClient的所有资源。

© www.soinside.com 2019 - 2024. All rights reserved.