使用套接字的 C# 客户端

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

我必须为聊天服务器编写一个简单的客户端,并且我想同时检查来自控制台和连接到服务器的套接字的输入。这是 C 中所需的行为,我想在 C# 中复制此行为:

while (true) {
    //make set of descriptors
    fd_set reads;
    FD_ZERO(&reads);
    FD_SET(client_socket, &reads);  
    FD_SET(0, &reads);
    select(client_socket+1, &reads, NULL, NULL, NULL);

    //handle user input from stdin
    if (FD_ISSET(0, &reads)) {
        ///
    }

    //handle message from server
    if (FD_ISSET(client_socket, &reads)) {
        ///
    }
}

我在 C# 中提出了这个解决方案,但我不确定它是否有效或高效。还有其他方法吗?:

var ongoingTasks = new List<Task> {getServerMsg, getUserMsg};
    
    while (true)
    {
        var finishedTask = await Task.WhenAny(ongoingTasks);
        if (finishedTask == getServerMsg) {
            OutputServerMsg();
            ongoingTasks.Remove(getServerMsg);
            getServerMsg = ReceiveMessageFromServer();
            ongoingTasks.Add(getServerMsg);
        } else if (finishedTask == getUserInput) {
             SendMsgToServer();
             ongoingTasks.Remove(getUserInput);
             getUserInput = ReceiveInputFromStdIn();
             ongoingTasks.Add(getUserInput);
        }
    }
c# c client
1个回答
0
投票

您正在考虑同步操作还是异步操作?不管怎样,这是异步版本,你的解决方案看起来太简单了

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        // Assuming you've connected your clientSocket to a server beforehand, otherwise call the connect as per below
        // clientSocket.Connect(serverEndPoint);

        // Run two tasks: one for listening to user input, another for receiving data from the server
        var receiveTask = ReceiveDataAsync(clientSocket);
        var userInputTask = ReadUserInputAsync(clientSocket);

        await Task.WhenAny(receiveTask, userInputTask);
    }

    static async Task ReceiveDataAsync(Socket clientSocket)
    {
        var buffer = new byte[1024];
        while (true)
        {
            var receiveEventArgs = new SocketAsyncEventArgs();
            receiveEventArgs.SetBuffer(buffer, 0, buffer.Length);

            var receiveTask = new TaskCompletionSource<bool>();
            receiveEventArgs.Completed += (sender, e) => receiveTask.SetResult(true);

            if (!clientSocket.ReceiveAsync(receiveEventArgs))
            {
                // Operation completed synchronously
                receiveTask.SetResult(true);
            }

            await receiveTask.Task; // Wait for data to be received

            var receivedBytes = receiveEventArgs.BytesTransferred;
            if (receivedBytes > 0)
            {
                string receivedText = Encoding.UTF8.GetString(buffer, 0, receivedBytes);
                Console.WriteLine($"Received: {receivedText}");
            }
            else
            {
                // Handle the server disconnecting
                Console.WriteLine("Server has disconnected.");
                break;
            }
        }
    }

    static async Task ReadUserInputAsync(Socket clientSocket)
    {
        while (true)
        {
            string userInput = await Task.Run(() => Console.ReadLine());

            var sendEventArgs = new SocketAsyncEventArgs();
            sendEventArgs.SetBuffer(Encoding.UTF8.GetBytes(userInput));

            var sendTask = new TaskCompletionSource<bool>();
            sendEventArgs.Completed += (sender, e) => sendTask.SetResult(true);

            if (!clientSocket.SendAsync(sendEventArgs))
            {
                // Operation completed synchronously
                sendTask.SetResult(true);
            }

            await sendTask.Task; // Wait for the data to be sent

            Console.WriteLine("Sent user input to server.");
        }
    }
}

ReceiveDataAsync 侦听来自服务器的数据。它使用 Socket.ReceiveAsync 从服务器异步接收数据。

ReadUserInputAsync 使用 Task.Run 在控制台中等待用户输入,以在单独的线程上运行同步阻塞操作 (Console.ReadLine()),从而使主线程保持响应。

Task.WhenAny 用于等待任一任务完成。这种方法可以保持 UI 响应(如果有的话)并且不会阻塞主线程。

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