我必须为聊天服务器编写一个简单的客户端,并且我想同时检查来自控制台和连接到服务器的套接字的输入。这是 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);
}
}
您正在考虑同步操作还是异步操作?不管怎样,这是异步版本,你的解决方案看起来太简单了
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 响应(如果有的话)并且不会阻塞主线程。