在现今软件开发中,网络编程是非常重要的一部分,本文简要介绍下网络编程的概念和实践。
C#网络编程的主要内容包括以下几个方面:
:
上图引用大佬的图,大家也关注一下,有技术有品质,有国有家,情怀满满的杨老师(不得不去仰慕一番哈哈)
https://blog.csdn.net/Eastmount/article/details/9321153
1. 底层网络协议类
如NetworkStream、TcpClient与TcpListener、UdpClient等,这些类提供了更底层的网络操作接口,适用于需要直接控制网络连接和数据处理的情况
1. TCP 通信
使用 TcpListener 和 TcpClient 进行 通讯
- TCP 服务器端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class TcpServerExample
{
static async Task Main(string[] args)
{
// 创建一个 TCP/IP 套接字
TcpListener listener = new TcpListener(IPAddress.Any, 13000);
listener.Start();
Console.WriteLine("Server started. Waiting for connections...");
while (true)
{
// 接受传入连接
TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("Client connected.");
// 处理客户端请求
_ = HandleClient(client);
}
}
static async Task HandleClient(TcpClient client)
{
try
{
NetworkStream stream = client.GetStream();
// 接收数据
byte[] buffer = new byte[256];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
string request = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + request);
// 发送响应
string response = "Hello, Client!";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await stream.WriteAsync(responseData, 0, responseData.Length);
Console.WriteLine("Sent: " + response);
// 关闭连接
client.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
- TCP 客户端示例
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class TcpClientExample
{
static async Task Main(string[] args)
{
try
{
// 创建一个 TCP/IP 套接字
TcpClient client = new TcpClient();
await client.ConnectAsync("127.0.0.1", 13000);
Console.WriteLine("Connected to server.");
NetworkStream stream = client.GetStream();
// 发送数据
string message = "Hello, Server!";
byte[] data = Encoding.ASCII.GetBytes(message);
await stream.WriteAsync(data, 0, data.Length);
Console.WriteLine("Sent: " + message);
// 接收响应
byte[] buffer = new byte[256];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + response);
// 关闭连接
client.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
2. UDP 通信
使用 UdpClient 进行通讯
- UDP 服务器端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class UdpServerExample
{
static async Task Main(string[] args)
{
// 创建一个 UDP/IP 套接字
UdpClient listener = new UdpClient(11000);
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
Console.WriteLine("UDP Server started. Listening on port 11000...");
while (true)
{
// 接收数据
byte[] buffer = await listener.ReceiveAsync();
string request = Encoding.ASCII.GetString(buffer);
Console.WriteLine("Received: " + request + " from " + remoteEndPoint.ToString());
// 发送响应
string response = "Hello, Client!";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await listener.SendAsync(responseData, responseData.Length, remoteEndPoint);
Console.WriteLine("Sent: " + response);
}
}
}
- UDP 客户端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class UdpClientExample
{
static async Task Main(string[] args)
{
try
{
// 创建一个 UDP/IP 套接字
UdpClient client = new UdpClient();
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000);
// 发送数据
string message = "Hello, Server!";
byte[] data = Encoding.ASCII.GetBytes(message);
await client.SendAsync(data, data.Length, remoteEP);
Console.WriteLine("Sent: " + message);
// 接收响应
UdpReceiveResult result = await client.ReceiveAsync();
string response = Encoding.ASCII.GetString(result.Buffer);
Console.WriteLine("Received: " + response + " from " + result.RemoteEndPoint.ToString());
// 关闭连接
client.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
3. 使用 NetworkStream 进行自定义协议通信
NetworkStream 提供了一个流式接口,可以用于读取和写入网络数据。以下是一个使用 NetworkStream 的示例,展示如何实现一个简单的自定义协议。
- 自定义协议服务器端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class CustomProtocolServerExample
{
static async Task Main(string[] args)
{
// 创建一个 TCP/IP 套接字
TcpListener listener = new TcpListener(IPAddress.Any, 13000);
listener.Start();
Console.WriteLine("Server started. Waiting for connections...");
while (true)
{
// 接受传入连接
TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("Client connected.");
// 处理客户端请求
_ = HandleClient(client);
}
}
static async Task HandleClient(TcpClient client)
{
try
{
NetworkStream stream = client.GetStream();
// 接收数据
byte[] buffer = new byte[256];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
string request = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + request);
// 解析自定义协议
string[] parts = request.Split(':');
if (parts.Length == 2 && parts[0] == "COMMAND")
{
string command = parts[1];
Console.WriteLine("Command: " + command);
// 处理命令并生成响应
string response = "ACK: Command received";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await stream.WriteAsync(responseData, 0, responseData.Length);
Console.WriteLine("Sent: " + response);
}
else
{
string response = "ERROR: Invalid command format";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await stream.WriteAsync(responseData, 0, responseData.Length);
Console.WriteLine("Sent: " + response);
}
// 关闭连接
client.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
- 自定义协议客户端示例
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class CustomProtocolClientExample
{
static async Task Main(string[] args)
{
try
{
// 创建一个 TCP/IP 套接字
TcpClient client = new TcpClient();
await client.ConnectAsync("127.0.0.1", 13000);
Console.WriteLine("Connected to server.");
NetworkStream stream = client.GetStream();
// 发送自定义协议命令
string message = "COMMAND:Hello";
byte[] data = Encoding.ASCII.GetBytes(message);
await stream.WriteAsync(data, 0, data.Length);
Console.WriteLine("Sent: " + message);
// 接收响应
byte[] buffer = new byte[256];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + response);
// 关闭连接
client.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
2.Socket编程
也就是我们常说的“套接字
”,Socket类在System.Net.Sockets
命名空间下,是最基本的网络操作类,封装了网络连接的创建和关闭、数据的收发以及网络状态监控等功能。通过Socket类,可以实现基于TCP
和UDP
的网络通信。
1. 使用 Socket 类进行 TCP 通信
TCP 服务器端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class TcpServerExample
{
static async Task Main(string[] args)
{
// 创建一个 TCP/IP 套接字
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 绑定套接字到本地端口
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 13000);
listener.Bind(localEndPoint);
// 监听传入连接
listener.Listen(10);
Console.WriteLine("Server started. Waiting for connections...");
while (true)
{
// 接受传入连接
Socket handler = await listener.AcceptAsync();
Console.WriteLine("Client connected.");
// 处理客户端请求
_ = HandleClient(handler);
}
}
static async Task HandleClient(Socket handler)
{
try
{
// 接收数据
byte[] buffer = new byte[256];
int bytesReceived = await handler.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None);
string request = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
Console.WriteLine("Received: " + request);
// 发送响应
string response = "Hello, Client!";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await handler.SendAsync(new ArraySegment<byte>(responseData), SocketFlags.None);
Console.WriteLine("Sent: " + response);
// 关闭连接
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
TCP 客户端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class TcpClientExample
{
static async Task Main(string[] args)
{
try
{
// 创建一个 TCP/IP 套接字
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 连接到服务器
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 13000);
await client.ConnectAsync(remoteEP);
Console.WriteLine("Connected to server.");
// 发送数据
string message = "Hello, Server!";
byte[] data = Encoding.ASCII.GetBytes(message);
await client.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
Console.WriteLine("Sent: " + message);
// 接收响应
byte[] buffer = new byte[256];
int bytesReceived = await client.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None);
string response = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
Console.WriteLine("Received: " + response);
// 关闭连接
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
2. 使用 Socket 类进行 UDP 通信
UDP 服务器端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class UdpServerExample
{
static async Task Main(string[] args)
{
// 创建一个 UDP/IP 套接字
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 绑定套接字到本地端口
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 11000);
listener.Bind(localEndPoint);
Console.WriteLine("UDP Server started. Waiting for messages...");
while (true)
{
// 接收数据
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] buffer = new byte[256];
int bytesReceived = await listener.ReceiveFromAsync(new ArraySegment<byte>(buffer), SocketFlags.None, remoteEndPoint);
string request = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
Console.WriteLine("Received: " + request + " from " + remoteEndPoint.ToString());
// 发送响应
string response = "Hello, Client!";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await listener.SendToAsync(new ArraySegment<byte>(responseData), SocketFlags.None, remoteEndPoint);
Console.WriteLine("Sent: " + response);
}
}
}
UDP 客户端示例
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class UdpClientExample
{
static async Task Main(string[] args)
{
try
{
// 创建一个 UDP/IP 套接字
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 连接到服务器
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000);
// 发送数据
string message = "Hello, Server!";
byte[] data = Encoding.ASCII.GetBytes(message);
await client.SendToAsync(new ArraySegment<byte>(data), SocketFlags.None, remoteEP);
Console.WriteLine("Sent: " + message);
// 接收响应
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] buffer = new byte[256];
int bytesReceived = await client.ReceiveFromAsync(new ArraySegment<byte>(buffer), SocketFlags.None, remoteEndPoint);
string response = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
Console.WriteLine("Received: " + response + " from " + remoteEndPoint.ToString());
// 关闭连接
client.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
注意事项
- 异常处理:使用 try-catch 块来捕获和处理异常。
- 资源管理:确保在使用完 Socket 后调用 Close 方法来释放资源。
- 并发处理:对于服务器端,通常需要处理多个客户端连接,可以使用多线程或异步编程来提高并发性能。
- 超时设置:对于 TCP 连接,可以设置超时时间来避免长时间等待。
3.WebSocket通信
WebSocket
是一种在单个TCP连接上进行全双工通讯的协议。可以使用 System.Net.WebSockets
命名空间中的类来创建 WebSocket 服务器和客户端。WebSocket通信常用于需要实时数据交换的应用场景,适用于需要实时数据交换的应用场景,如实时聊天、在线游戏、股票行情等。
1.WebSocket 服务器端示例
以下是一个简单的 WebSocket 服务器端示例,使用 HttpListener
来处理 HTTP 请求并升级为 WebSocket 连接。
using System;
using System.IO;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class WebSocketServerExample
{
static async Task Main(string[] args)
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8080/");
listener.Start();
Console.WriteLine("WebSocket Server started. Listening on ws://localhost:8080/");
while (true)
{
HttpListenerContext context = await listener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null);
_ = HandleWebSocketConnection(webSocketContext.WebSocket);
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Response.Close();
}
}
}
static async Task HandleWebSocketConnection(WebSocket webSocket)
{
byte[] buffer = new byte[1024 * 4];
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!result.CloseStatus.HasValue)
{
string userMessage = Encoding.UTF8.GetString(new ArraySegment<byte>(buffer, 0, result.Count));
Console.WriteLine("Received: " + userMessage);
//来自客户端:将消息回传给客户端
byte[] responseBuffer = Encoding.UTF8.GetBytes("Echo: " + userMessage);
await webSocket.SendAsync(new ArraySegment<byte>(responseBuffer), result.MessageType, result.EndOfMessage, CancellationToken.None);
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
webSocket.Dispose();
}
}
2.WebSocket 客户端示例
以下是一个简单的 WebSocket
客户端示例,使用 ClientWebSocket
类来连接 WebSocket 服务器并进行通信。
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class WebSocketClientExample
{
static async Task Main(string[] args)
{
using (ClientWebSocket webSocket = new ClientWebSocket())
{
Uri serverUri = new Uri("ws://localhost:8080/");
await webSocket.ConnectAsync(serverUri, CancellationToken.None);
Console.WriteLine("Connected to server.");
byte[] buffer = new byte[1024 * 4];
// 在单独的任务中开始接收消息
_ = ReceiveMessages(webSocket, buffer);
// 向服务器发送消息
while (webSocket.State == WebSocketState.Open)
{
Console.Write("Enter message to send: ");
string message = Console.ReadLine();
byte[] messageBuffer = Encoding.UTF8.GetBytes(message);
await webSocket.SendAsync(new ArraySegment<byte>(messageBuffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
static async Task ReceiveMessages(ClientWebSocket webSocket, byte[] buffer)
{
while (webSocket.State == WebSocketState.Open)
{
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
break;
}
string receivedMessage = Encoding.UTF8.GetString(new ArraySegment<byte>(buffer, 0, result.Count));
Console.WriteLine("Received: " + receivedMessage);
}
}
}
注意事项
- 异常处理:使用 try-catch 块来捕获和处理异常,特别是网络相关的异常。
- 资源管理:确保在使用完 WebSocket 后调用 CloseAsync 和 Dispose 方法来释放资源。
- 并发处理:对于服务器端,通常需要处理多个客户端连接,可以使用多线程或异步编程来提高并发性能。
- 安全性:在生产环境中,建议使用
wss://(WebSocket Secure)
来加密通信,防止数据泄露。 - 心跳机制:为了保持连接活跃,可以定期发送心跳消息,防止中间设备关闭空闲连接。
4. HTTP请求:
可以使用HttpClient、WebClient、HttpRequestMessage和HttpMessageHandler等类来发送HTTP请求。这些类提供了发送GET、POST等请求的方法,并支持异步操作和身份验证等功能。
1. HttpClient
HttpClient
是一个现代的、高效的 HTTP 客户端,支持异步操作,适用于 .NET Core 和 .NET Framework。
主要方法
• GetAsync:发送 GET 请求。
• PostAsync:发送 POST 请求。
• PutAsync:发送 PUT 请求。
• DeleteAsync:发送 DELETE 请求。
• SendAsync:发送任意类型的 HTTP 请求。
注意
• 单例模式:HttpClient 实例应该尽量复用,而不是每次请求都创建新的实例。频繁创建 HttpClient 实例会导致资源泄漏和性能问题。
• 异常处理:使用 EnsureSuccessStatusCode
方法来确保请求成功,否则会抛出 HttpRequestException
。
• 超时设置:设置合理的超时时间,避免长时间等待。
• 取消请求:使用 CancellationToken 来取消长时间运行的请求。
示例代码
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class HttpClientExample
{
private static readonly HttpClient client = new HttpClient();
static async Task Main(string[] args)
{
try
{
// 设置超时时间
client.Timeout = TimeSpan.FromSeconds(30);
// 发送 GET 请求
HttpResponseMessage response = await client.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode(); // 确保请求成功
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("GET Response: " + responseBody);
// 发送 POST 请求
var content = new StringContent("{\"key\":\"value\"}", System.Text.Encoding.UTF8, "application/json");
response = await client.PostAsync("https://api.example.com/post", content);
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("POST Response: " + responseBody);
}
catch (HttpRequestException ex)
{
Console.WriteLine("HTTP Error: " + ex.Message);
}
catch (TaskCanceledException ex)
{
Console.WriteLine("Request canceled: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
2. WebClient
WebClient
是一个较老的类,提供了简单的同步和异步方法来下载和上传数据。虽然它仍然可用,但推荐使用 HttpClient。
主要方法
• DownloadString:下载字符串内容。
• UploadString:上传字符串内容。
• DownloadFile:下载文件。
• UploadFile:上传文件。
注意
• 同步方法:WebClient
的同步方法会阻塞当前线程,建议使用异步方法。
• 异常处理:使用 try-catch
块来捕获和处理异常。
• 资源管理:使用 using
语句来确保 WebClient 实例在使用后被正确释放。
示例代码
using System;
using System.Net;
class WebClientExample
{
static void Main(string[] args)
{
try
{
using (WebClient client = new WebClient())
{
// 下载字符串内容
string response = client.DownloadString("https://api.example.com/data");
Console.WriteLine("GET Response: " + response);
// 上传字符串内容
string uploadData = "{\"key\":\"value\"}";
response = client.UploadString("https://api.example.com/post", uploadData);
Console.WriteLine("POST Response: " + response);
}
}
catch (WebException ex)
{
Console.WriteLine("Web Error: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
3. HttpRequestMessage
HttpRequestMessage 用于构建 HTTP 请求,通常与 HttpClient 一起使用,提供更细粒度的控制。
注意
• 请求头设置:根据需要设置请求头,例如 Content-Type
、Authorization
等。
• 请求体设置:对于 POST
、PUT
等请求,需要设置请求体内容。
• 响应处理:处理响应内容时,注意检查响应状态码和内容类型。
示例代码
using System;
using System.Net.Http;
using System.Threading.Tasks;
class HttpRequestMessageExample
{
static async Task Main(string[] args)
{
using (HttpClient client = new HttpClient())
{
try
{
// 构建 GET 请求
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data");
HttpResponseMessage response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("GET Response: " + responseBody);
// 构建 POST 请求
request = new HttpRequestMessage(HttpMethod.Post, "https://api.example.com/post")
{
Content = new StringContent("{\"key\":\"value\"}", System.Text.Encoding.UTF8, "application/json")
};
response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("POST Response: " + responseBody);
}
catch (HttpRequestException ex)
{
Console.WriteLine("HTTP Error: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
}
4. HttpMessageHandler
HttpMessageHandler
是 HttpClient 的基础组件,用于处理 HTTP 请求和响应。通常情况下,开发者不需要直接使用 HttpMessageHandler,但在某些高级场景中,可以自定义消息处理器来实现特定的功能。
注意
• 自定义处理:在 SendAsync
方法中添加自定义逻辑,例如日志记录、请求拦截等。
• 资源管理:确保自定义的消息处理器在使用后被正确释放。
示例代码
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class CustomMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
// 在发送请求之前添加自定义逻辑
Console.WriteLine("Sending request to: " + request.RequestUri);
// 调用基类的 SendAsync 方法
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// 在接收响应之后添加自定义逻辑
Console.WriteLine("Received response from: " + request.RequestUri);
return response;
}
catch (Exception ex)
{
Console.WriteLine("Error in message handler: " + ex.Message);
throw;
}
}
}
class HttpMessageHandlerExample
{
static async Task Main(string[] args)
{
try
{
// 创建自定义消息处理器
CustomMessageHandler handler = new CustomMessageHandler();
// 使用自定义消息处理器创建 HttpClient
using (HttpClient client = new HttpClient(handler))
{
// 发送 GET 请求
HttpResponseMessage response = await client.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("GET Response: " + responseBody);
}
}
catch (HttpRequestException ex)
{
Console.WriteLine("HTTP Error: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
总结
• HttpClient:现代、高效的 HTTP 客户端,支持异步操作,推荐使用;单例模式、异常处理、超时设置、取消请求。
• WebClient:较老的类,简单易用,但推荐使用 HttpClient;同步方法、异常处理、资源管理。
• HttpRequestMessage:用于构建 HTTP 请求,通常与 HttpClient 一起使用;请求头设置、请求体设置、响应处理。
• HttpMessageHandler:用于处理 HTTP 请求和响应,通常用于高级场景;:自定义处理、资源管理。
5.网络安全
C# 网络编程中有效地保护应用程序的安全。确保数据传输的安全性、正确处理用户输入、实施适当的身份验证和授权机制,以及遵循其他最佳实践,都是构建安全网络应用程序的关键步骤,包括SSL/TLS加密、密码安全存储、防止SQL注入、防止跨站脚本攻击(XSS)、防止跨站请求伪造(CSRF)、身份验证和授权等。
1. SSL/TLS 加密
使用 SSL/TLS
可以确保数据在传输过程中不被窃听或篡改。
示例:使用 HttpClient
进行 HTTPS 请求
using System;
using System.Net.Http;
using System.Threading.Tasks;
class HttpsExample
{
static async Task Main(string[] args)
{
using (HttpClient client = new HttpClient())
{
try
{
HttpResponseMessage response = await client.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ", e.Message);
}
}
}
}
2. 密码安全存储
使用哈希算法和盐值来安全地存储密码。
示例:使用 PasswordHasher
进行密码哈希
using Microsoft.AspNetCore.Identity;
using System;
class PasswordStorageExample
{
static void Main(string[] args)
{
var passwordHasher = new PasswordHasher<string>();
string password = "securePassword123";
string hashedPassword = passwordHasher.HashPassword(null, password);
Console.WriteLine("Hashed Password: " + hashedPassword);
PasswordVerificationResult result = passwordHasher.VerifyHashedPassword(null, hashedPassword, password);
Console.WriteLine("Verification Result: " + result);
}
}
3. 防止 SQL 注入
使用参数化查询来防止 SQL
注入。
示例:使用 SqlCommand
进行参数化查询
using System;
using System.Data.SqlClient;
class SqlInjectionExample
{
static void Main(string[] args)
{
string connectionString = "your_connection_string_here";
string query = "SELECT * FROM Users WHERE Username = @Username AND Password = @Password";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@Username", "user1");
command.Parameters.AddWithValue("@Password", "pass1");
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader["Username"]);
}
}
}
}
4. 防止跨站脚本攻击 (XSS)
对用户输入进行适当的转义和验证。
示例:使用 HttpUtility.HtmlEncode
转义 HTML
内容
using System;
using System.Web;
class XssExample
{
static void Main(string[] args)
{
string userInput = "<script>alert('XSS')</script>";
string safeOutput = HttpUtility.HtmlEncode(userInput);
Console.WriteLine("Safe Output: " + safeOutput);
}
}
5. 防止跨站请求伪造 (CSRF)
使用 CSRF 令牌来防止跨站请求伪造。
示例:ASP.NET Core
中的 CSRF
保护
在 ASP.NET Core 中,CSRF 保护是默认启用的。确保在表单中包含 CSRF 令牌。
@model YourModel
<form method="post">
@Html.AntiForgeryToken()
<!-- Form fields here -->
<button type="submit">Submit</button>
</form>
6. 身份验证和授权
使用身份验证和授权机制来保护应用程序。
示例:ASP.NET Core 中的身份验证和授权
在 Startup.cs
中配置身份验证和授权。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie();
services.AddAuthorization();
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
7. 其他安全措施
• 输入验证:对所有用户输入进行验证,确保其符合预期格式。
• 输出编码:对输出进行适当的编码,防止 XSS
攻击。
• 最小权限原则:确保应用程序以最小权限运行,限制不必要的权限。
• 定期更新和补丁:定期更新所有依赖库和框架,应用最新的安全补丁。
• 日志记录和监控:实施详细的日志记录和监控,以便及时发现和响应安全事件。
6.多线程与并发(待续)
• Thread 类:System.Threading.Thread 用于创建和管理线程。
• ThreadPool 类:System.Threading.ThreadPool 用于管理线程池。
• Task 并发:使用 Task.Run 和 Parallel 类进行并行任务处理。
7.序列化与反序列化(待续)
• JSON 序列化:使用 System.Text.Json.JsonSerializer 进行 JSON 序列化和反序列化。
• XML 序列化:使用 System.Xml.Serialization.XmlSerializer 进行 XML 序列化和反序列化。
8.网络配置(待续)
• 配置文件:使用 appsettings.json 或 app.config 配置网络参数。
• 环境变量:从环境变量中读取网络配置信息。