在c#中Task是什么
在C#中,Task
是一个表示异步操作的类,它是.NET Framework中的一个核心组件,用于实现异步编程模型。Task
允许开发者编写非阻塞的代码,这样可以提高应用程序的响应性和性能。
以下是一些关于 Task
的关键点:
-
表示异步操作:
Task
对象代表了一个可能已经完成或尚未完成的异步操作。 -
返回值:
Task
可以返回一个值,通过Task<TResult>
实现,其中TResult
是结果的类型。 -
状态:
Task
对象有几种状态,如Running
、WaitingToRun
、RanToCompletion
、Faulted
(出现错误)、Canceled
(被取消)等。 -
异常处理:如果异步操作中发生异常,
Task
对象会捕获这些异常,并且可以通过Task.Exception
属性访问它们。 -
等待完成:可以使用
Task.Wait()
或者await
关键字来等待Task
完成。 -
取消:可以通过调用
Task
对象的Cancel()
方法来尝试取消一个正在运行的异步操作。 -
继续操作:可以使用
ContinueWith
方法来链式调用,当一个Task
完成时,自动启动另一个Task
。 -
并行执行:可以使用
Task.WhenAll
或Task.WhenAny
来处理多个Task
的并行执行。 -
配置:
Task
可以配置为同步或异步执行,以及配置其调度器等。 -
使用场景:
Task
广泛用于需要异步执行的场合,如I/O操作、网络请求、长时间运行的计算任务等
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Task task = Task.Run(() => DoSomeWork());
await task; // 等待任务完成
Console.WriteLine("Task completed.");
}
static void DoSomeWork()
{
// 模拟一些工作
Task.Delay(1000).Wait();
Console.WriteLine("Work done.");
}
}
DoSomeWork
方法在一个新的 Task
中异步执行,Main
方法使用 await
关键字等待这个 Task
完成。这种方式允许 Main
方法在等待时释放控制权,使得应用程序可以继续响应其他事件或操作。
Connect和BeginConnect的区别
在C#中,Connect
和 BeginConnect
是用于建立网络连接的方法,通常在 Socket
类中使用。它们的主要区别在于同步和异步操作:
-
Connect:
-
Connect
是一个同步方法。 -
当调用
Connect
方法时,当前线程会被阻塞,直到连接建立成功或失败。 -
它返回
void
,并且可能引发异常,例如SocketException
,如果连接失败。
-
-
BeginConnect:
-
BeginConnect
是一个异步方法。 -
当调用
BeginConnect
方法时,它立即返回,不阻塞当前线程,允许应用程序继续执行其他任务。 -
它返回一个
IAsyncResult
对象,这个对象可以用于跟踪异步操作的进度。 -
为了完成连接,你需要使用
EndConnect
方法,它将等待异步操作完成,并返回一个SocketError
枚举值来指示操作的结果。
-
使用 Connect:
using System;
using System.Net.Sockets;
class Program
{
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect("www.example.com", 80); // 同步连接
Console.WriteLine("Connected to the server.");
// 进行数据传输...
}
catch (SocketException e)
{
Console.WriteLine("Connection failed: " + e.Message);
}
}
}
使用 BeginConnect:
using System;
using System.Net.Sockets;
class Program
{
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect("www.example.com", 80, new AsyncCallback(ConnectCallback), socket);
// 应用程序可以继续执行其他任务...
Console.ReadLine(); // 等待用户输入,防止程序退出
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
socket.EndConnect(ar); // 完成连接
Console.WriteLine("Connected to the server.");
// 进行数据传输...
}
catch (Exception e)
{
Console.WriteLine("Connection failed: " + e.Message);
}
}
}
在异步示例中,BeginConnect
允许应用程序在等待连接建立的同时执行其他任务。当连接建立后,ConnectCallback
回调方法会被调用,以完成连接并进行后续操作。这种方式特别适用于需要高响应性的应用程序,例如用户界面应用程序。
EndConnect 方法
在C#中,EndConnect
方法是与 BeginConnect
方法配合使用的,用于完成一个异步的网络连接操作。当你使用 BeginConnect
方法开始一个异步连接时,EndConnect
将被用来确定连接是否成功完成,或者在连接过程中是否发生了错误。
以下是 EndConnect
方法的一些关键点:
-
用途:
EndConnect
用于结束由BeginConnect
方法启动的异步连接尝试。 -
参数:
EndConnect
方法接受一个IAsyncResult
对象作为参数,这个对象是由BeginConnect
方法返回的,用于跟踪异步操作的状态。 -
返回值:
EndConnect
不返回任何值,但它会设置Socket
对象的状态,以便你可以检查连接是否成功。 -
错误处理:如果连接失败,
EndConnect
会抛出SocketException
。然而,Socket
类提供了SocketError
枚举,你可以在调用EndConnect
之前检查IAsyncResult
对象的SocketError
属性来提前发现错误。 -
同步行为:尽管
EndConnect
是用来结束异步操作的,但它本身是同步的。调用EndConnect
的线程将会被阻塞,直到异步操作完成。 -
使用场景:
EndConnect
通常在异步回调方法中被调用,例如在BeginConnect
方法的AsyncCallback
委托中。
using System;
using System.Net.Sockets;
class Program
{
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 开始异步连接
socket.BeginConnect("www.example.com", 80, new AsyncCallback(ConnectCallback), socket);
// 应用程序可以继续执行其他任务...
Console.ReadLine(); // 等待用户输入,防止程序退出
}
private static void ConnectCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
try
{
// 完成异步连接
socket.EndConnect(ar);
Console.WriteLine("Connected to the server.");
// 检查是否有错误发生
if (ar.IsCompleted && ar.AsyncWaitHandle.WaitOne(0))
{
SocketError error = (SocketError)ar.AsyncState;
if (error != SocketError.Success)
{
throw new SocketException((int)error);
}
}
// 进行数据传输...
}
catch (Exception e)
{
Console.WriteLine("Connection failed: " + e.Message);
}
}
}
BeginConnect
启动了异步连接尝试,并且指定了一个回调方法 ConnectCallback
。当连接尝试完成时,ConnectCallback
会被调用,然后 EndConnect
被用来结束连接尝试,并检查是否成功。如果连接成功,应用程序可以继续进行数据传输或其他操作。如果连接失败,异常将被捕获并处理。
长连接 短连接区别
长连接(Long Connection)和短连接(Short Connection)是网络通信中两种不同的连接模式,它们在建立连接、使用资源、适用场景等方面有所区别:
-
连接建立:
- 长连接:一旦建立,连接会保持打开状态,直到客户端或服务器端明确关闭连接。适用于需要持续通信的场景。
- 短连接:每次通信都需要建立一个新的连接,通信完成后立即关闭连接。适用于偶尔的、短暂的通信。
-
资源消耗:
- 长连接:由于连接保持打开状态,可能会占用更多的服务器资源,尤其是在大量客户端同时连接时。
- 短连接:每次通信结束后释放连接资源,对服务器资源的占用相对较少,但频繁的连接和断开可能会增加网络延迟。
-
适用场景:
- 长连接:适用于需要频繁通信、实时性要求高的应用,如即时通讯、在线游戏、实时数据传输等。
- 短连接:适用于通信频率较低、数据量小的场景,如HTTP请求、FTP传输等。
-
连接稳定性:
- 长连接:由于连接持续存在,通常可以提供更稳定的通信环境。
- 短连接:每次通信都需要重新建立连接,可能会受到网络波动的影响,稳定性相对较低。
-
维护成本:
- 长连接:需要更多的维护工作,如心跳检测、连接超时处理等,以确保连接的持续有效性。
- 短连接:由于连接生命周期短,维护成本相对较低。
-
性能影响:
- 长连接:可以减少连接建立和断开的开销,提高通信效率,但可能会因为长时间占用资源而影响性能。
- 短连接:每次通信都需要建立和断开连接,可能会增加通信的延迟,但可以更灵活地分配资源。
-
安全性:
- 长连接:由于连接保持时间较长,可能需要更多的安全措施来防止潜在的安全风险。
- 短连接:每次通信结束后连接即关闭,可以降低一些安全风险,但也需要确保每次通信的安全。
Socket 断线重连
// 拿到最新的状态
Socket socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
// 三次握手
socket.Connect(new IPEndPoint(IPAddress.Parse("192.168.2.1"), 102));
Console.WriteLine(socket.Connected);// 保留最后一次操作时的状态,不是实时的状态
while (true)
{
// 心跳请求
Thread.Sleep(1000);
bool state = !(!socket.Connected || (socket.Poll(1, SelectMode.SelectRead) && socket.Poll(1, SelectMode.SelectWrite) && (socket.Available == 0)));// 返回True :连接正常
if (state)
{
Console.WriteLine("连接正常");
socket.Shutdown(SocketShutdown.Both);
socket.Dispose();
}
else
{
Console.WriteLine("连接断开");
socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
try
{
// 大概20秒时间
//socket.Connect(new IPEndPoint(IPAddress.Parse("192.168.2.1"), 102));
}
catch (Exception ex)
{
Console.WriteLine("重新连接失败");
Console.WriteLine(ex.Message);
}
var result = socket.BeginConnect(new IPEndPoint(IPAddress.Parse("192.168.2.1"), 102), new AsyncCallback(r =>
{
//
Console.WriteLine(r.AsyncState);
if (!r.IsCompleted) // 连接请求的动作 执行完成 不包括连接状态
socket.EndConnect(r);
Console.WriteLine("回调执行");
}), null);
bool s = result.AsyncWaitHandle.WaitOne(1000);
if (s)// 连接成功后
{
Console.WriteLine("重新连接");
}
else
{
// 连接的时候 异步,在1秒钟时间内 没有连接成功 跳出
try
{
//socket.EndConnect(result); // 销毁之前的连接请求 卡线程
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("重连失败");
}
}
//重连 使用 发送业务请求 执行连接判断
}
Socket TCP 服务端
SocketType.Stream,
ProtocolType.Tcp
Socket socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, 9090));// IP 端口 指定
127.0.0.1 localhost 192.168...
socket.Listen(1);// 启动服务监听 参数的意思:等待连接的数量
Task.Run(() =>
{
while (true)
{
Socket client = socket.Accept();// 同步 卡住线程
clientList.Add(client);
Task.Run(() =>
{
while (true)
{
// 接收到一个消息后 转发出去 应用层协议
byte[] buffer = new byte[1024];
client.Receive(buffer);// 卡线程
string msg = Encoding.UTF8.GetString(buffer);
msg = msg.Replace("\0", "");
Console.WriteLine("从客户端接收到:" + msg);
// PLC 接收到特定的报文 byte[]
// 执行处理逻辑 I0.0
// 将值马上返回给客户端
msg += " - Server";
client.Send(Encoding.UTF8.GetBytes(msg));//
//using (Socket client = socket.Accept())
//{
// client.Shutdown();
//}
//client.Dispose();
}//
});
}
});
var state = socket.BeginAccept(new AsyncCallback(result =>
{
Console.WriteLine(result.IsCompleted);
}), null);
state.AsyncWaitHandle.WaitOne();// 等待执行
Console.WriteLine("服务监听已启动...");
Socket TCP 客户端
// 创建一个TCP客户端 PLC 服务端 客户
using (Socket socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp))
{
socket.ReceiveTimeout = 5000;
socket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9080));// 成功
// 为什么马上就下线了 using Dispose
byte[] bytes = Encoding.UTF8.GetBytes("Request");
// 成功
socket.Send(bytes);
// 响应
byte[] buffer = new byte[1024];
try
{
socket.Receive(buffer);// 服务端未响应;链路异常
// 要求:在一定时间内 如果未接收到响应 超时处理
string msg = Encoding.UTF8.GetString(buffer).Replace("\0", "");
Console.WriteLine(Encoding.UTF8.GetString(buffer));
//socket.Shutdown(SocketShutdown.Both);
}
catch (Exception ex)
{
Console.WriteLine("接收超时");
Console.WriteLine(ex.Message);
}
}