学习目标
- 掌握HTTP客户端编程
- 理解TCP和UDP网络通信
- 学习WebSocket实时通信
- 掌握网络编程最佳实践
- 了解网络安全和性能优化
17.1 HTTP客户端编程
HttpClient基础使用
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
// HTTP客户端基础示例
public class HttpClientBasics
{
private static readonly HttpClient _httpClient = new HttpClient();
static HttpClientBasics()
{
// 配置HttpClient
_httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
_httpClient.Timeout = TimeSpan.FromSeconds(30);
}
// GET请求
public static async Task<string> GetStringAsync(string url)
{
try
{
var response = await _httpClient.GetStringAsync(url);
return response;
}
catch (HttpRequestException ex)
{
Console.WriteLine($"HTTP请求错误: {ex.Message}");
throw;
}
catch (TaskCanceledException ex)
{
Console.WriteLine($"请求超时: {ex.Message}");
throw;
}
}
// GET请求并获取详细响应
public static async Task<HttpResponseMessage> GetAsync(string url)
{
var response = await _httpClient.GetAsync(url);
Console.WriteLine($"状态码: {response.StatusCode}");
Console.WriteLine($"响应头: {response.Headers}");
Console.WriteLine($"内容类型: {response.Content.Headers.ContentType}");
return response;
}
// POST请求发送JSON数据
public static async Task<T> PostJsonAsync<T>(string url, object data)
{
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(responseJson);
}
// PUT请求
public static async Task<bool> PutAsync(string url, object data)
{
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PutAsync(url, content);
return response.IsSuccessStatusCode;
}
// DELETE请求
public static async Task<bool> DeleteAsync(string url)
{
var response = await _httpClient.DeleteAsync(url);
return response.IsSuccessStatusCode;
}
// 文件上传
public static async Task<string> UploadFileAsync(string url, string filePath)
{
using var form = new MultipartFormDataContent();
using var fileStream = File.OpenRead(filePath);
using var fileContent = new StreamContent(fileStream);
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
form.Add(fileContent, "file", Path.GetFileName(filePath));
var response = await _httpClient.PostAsync(url, form);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// 文件下载
public static async Task DownloadFileAsync(string url, string filePath)
{
using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using var contentStream = await response.Content.ReadAsStreamAsync();
using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
await contentStream.CopyToAsync(fileStream);
}
// 带进度的文件下载
public static async Task DownloadFileWithProgressAsync(string url, string filePath, IProgress<double> progress = null)
{
using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength ?? 0;
using var contentStream = await response.Content.ReadAsStreamAsync();
using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
var buffer = new byte[8192];
var totalBytesRead = 0L;
int bytesRead;
while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
if (totalBytes > 0)
{
var progressPercentage = (double)totalBytesRead / totalBytes * 100;
progress?.Report(progressPercentage);
}
}
}
}
// 使用示例
public class HttpClientDemo
{
public static async Task DemoHttpClient()
{
// GET请求
var html = await HttpClientBasics.GetStringAsync("https://httpbin.org/get");
Console.WriteLine($"GET响应: {html}");
// POST请求
var postData = new { name = "张三", age = 25 };
var postResponse = await HttpClientBasics.PostJsonAsync<dynamic>("https://httpbin.org/post", postData);
Console.WriteLine($"POST响应: {postResponse}");
// 文件下载
var progress = new Progress<double>(percentage =>
Console.WriteLine($"下载进度: {percentage:F1}%"));
await HttpClientBasics.DownloadFileWithProgressAsync(
"https://httpbin.org/bytes/1024",
"downloaded_file.bin",
progress);
}
}
17.3 UDP网络编程
UDP服务器和客户端
using System.Net;
using System.Net.Sockets;
using System.Text;
// UDP服务器
public class UdpServer
{
private UdpClient _udpServer;
private bool _isRunning;
private IPEndPoint _localEndPoint;
public event Action<string, IPEndPoint> MessageReceived;
public async Task StartAsync(int port)
{
_localEndPoint = new IPEndPoint(IPAddress.Any, port);
_udpServer = new UdpClient(_localEndPoint);
_isRunning = true;
Console.WriteLine($"UDP服务器启动在端口 {port}");
// 开始接收数据
_ = Task.Run(ReceiveMessagesAsync);
}
private async Task ReceiveMessagesAsync()
{
while (_isRunning)
{
try
{
var result = await _udpServer.ReceiveAsync();
var message = Encoding.UTF8.GetString(result.Buffer);
var clientEndPoint = result.RemoteEndPoint;
MessageReceived?.Invoke(message, clientEndPoint);
Console.WriteLine($"收到来自 {clientEndPoint} 的消息: {message}");
// 回复消息
var response = $"服务器收到: {message}";
await SendMessageAsync(response, clientEndPoint);
}
catch (ObjectDisposedException)
{
// 服务器已停止
break;
}
catch (Exception ex)
{
Console.WriteLine($"接收UDP消息时出错: {ex.Message}");
}
}
}
public async Task SendMessageAsync(string message, IPEndPoint clientEndPoint)
{
try
{
var messageBytes = Encoding.UTF8.GetBytes(message);
await _udpServer.SendAsync(messageBytes, messageBytes.Length, clientEndPoint);
}
catch (Exception ex)
{
Console.WriteLine($"发送UDP消息失败: {ex.Message}");
}
}
// 广播消息
public async Task BroadcastAsync(string message, int port)
{
try
{
var broadcastEndPoint = new IPEndPoint(IPAddress.Broadcast, port);
var messageBytes = Encoding.UTF8.GetBytes(message);
using var broadcastClient = new UdpClient();
broadcastClient.EnableBroadcast = true;
await broadcastClient.SendAsync(messageBytes, messageBytes.Length, broadcastEndPoint);
Console.WriteLine($"广播消息: {message}");
}
catch (Exception ex)
{
Console.WriteLine($"广播消息失败: {ex.Message}");
}
}
public void Stop()
{
_isRunning = false;
_udpServer?.Close();
Console.WriteLine("UDP服务器已停止");
}
}
// UDP客户端
public class UdpClientWrapper
{
private UdpClient _udpClient;
private IPEndPoint _serverEndPoint;
private bool _isListening;
public event Action<string> MessageReceived;
public void Connect(string serverAddress, int serverPort)
{
_serverEndPoint = new IPEndPoint(IPAddress.Parse(serverAddress), serverPort);
_udpClient = new UdpClient();
_isListening = true;
Console.WriteLine($"UDP客户端连接到 {serverAddress}:{serverPort}");
// 开始监听服务器响应
_ = Task.Run(ListenForResponsesAsync);
}
private async Task ListenForResponsesAsync()
{
while (_isListening)
{
try
{
var result = await _udpClient.ReceiveAsync();
var message = Encoding.UTF8.GetString(result.Buffer);
MessageReceived?.Invoke(message);
}
catch (ObjectDisposedException)
{
// 客户端已关闭
break;
}
catch (Exception ex)
{
Console.WriteLine($"接收UDP响应时出错: {ex.Message}");
}
}
}
public async Task SendMessageAsync(string message)
{
try
{
var messageBytes = Encoding.UTF8.GetBytes(message);
await _udpClient.SendAsync(messageBytes, messageBytes.Length, _serverEndPoint);
Console.WriteLine($"发送消息: {message}");
}
catch (Exception ex)
{
Console.WriteLine($"发送UDP消息失败: {ex.Message}");
}
}
public void Disconnect()
{
_isListening = false;
_udpClient?.Close();
Console.WriteLine("UDP客户端已断开");
}
}
// UDP通信示例
public class UdpDemo
{
public static async Task DemoUdpServer()
{
var server = new UdpServer();
server.MessageReceived += (message, client) =>
Console.WriteLine($"处理来自 {client} 的消息: {message}");
await server.StartAsync(8081);
// 模拟广播
await Task.Delay(3000);
await server.BroadcastAsync("服务器广播消息", 8082);
Console.WriteLine("按任意键停止UDP服务器...");
Console.ReadKey();
server.Stop();
}
public static async Task DemoUdpClient()
{
var client = new UdpClientWrapper();
client.MessageReceived += message =>
Console.WriteLine($"收到服务器响应: {message}");
client.Connect("127.0.0.1", 8081);
// 发送消息
await client.SendMessageAsync("Hello UDP Server!");
await client.SendMessageAsync("How are you?");
await Task.Delay(2000);
Console.WriteLine("按任意键断开UDP客户端...");
Console.ReadKey();
client.Disconnect();
}
}
17.4 WebSocket编程
WebSocket服务器
using System.Net;
using System.Net.WebSockets;
using System.Text;
// WebSocket服务器
public class WebSocketServer
{
private HttpListener _httpListener;
private bool _isRunning;
private readonly List<WebSocket> _connectedClients = new();
private readonly object _clientsLock = new();
public event Action<string, WebSocket> MessageReceived;
public event Action<WebSocket> ClientConnected;
public event Action<WebSocket> ClientDisconnected;
public async Task StartAsync(string prefix)
{
_httpListener = new HttpListener();
_httpListener.Prefixes.Add(prefix);
_httpListener.Start();
_isRunning = true;
Console.WriteLine($"WebSocket服务器启动: {prefix}");
// 开始接受连接
_ = Task.Run(AcceptConnectionsAsync);
}
private async Task AcceptConnectionsAsync()
{
while (_isRunning)
{
try
{
var context = await _httpListener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
_ = Task.Run(() => HandleWebSocketAsync(context));
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
catch (ObjectDisposedException)
{
// 服务器已停止
break;
}
catch (Exception ex)
{
Console.WriteLine($"接受WebSocket连接时出错: {ex.Message}");
}
}
}
private async Task HandleWebSocketAsync(HttpListenerContext context)
{
WebSocket webSocket = null;
try
{
var webSocketContext = await context.AcceptWebSocketAsync(null);
webSocket = webSocketContext.WebSocket;
lock (_clientsLock)
{
_connectedClients.Add(webSocket);
}
ClientConnected?.Invoke(webSocket);
Console.WriteLine($"WebSocket客户端已连接,当前连接数: {_connectedClients.Count}");
// 处理消息
await ProcessWebSocketMessagesAsync(webSocket);
}
catch (Exception ex)
{
Console.WriteLine($"处理WebSocket连接时出错: {ex.Message}");
}
finally
{
if (webSocket != null)
{
lock (_clientsLock)
{
_connectedClients.Remove(webSocket);
}
ClientDisconnected?.Invoke(webSocket);
Console.WriteLine($"WebSocket客户端已断开,当前连接数: {_connectedClients.Count}");
}
}
}
private async Task ProcessWebSocketMessagesAsync(WebSocket webSocket)
{
var buffer = new byte[4096];
while (webSocket.State == WebSocketState.Open)
{
try
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
MessageReceived?.Invoke(message, webSocket);
// 回显消息
var response = $"服务器收到: {message}";
await SendMessageAsync(webSocket, response);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "关闭连接", CancellationToken.None);
break;
}
}
catch (WebSocketException ex)
{
Console.WriteLine($"WebSocket通信错误: {ex.Message}");
break;
}
}
}
public async Task SendMessageAsync(WebSocket webSocket, string message)
{
if (webSocket.State == WebSocketState.Open)
{
try
{
var messageBytes = Encoding.UTF8.GetBytes(message);
await webSocket.SendAsync(
new ArraySegment<byte>(messageBytes),
WebSocketMessageType.Text,
true,
CancellationToken.None);
}
catch (Exception ex)
{
Console.WriteLine($"发送WebSocket消息失败: {ex.Message}");
}
}
}
// 广播消息给所有连接的客户端
public async Task BroadcastAsync(string message)
{
var clientsCopy = new List<WebSocket>();
lock (_clientsLock)
{
clientsCopy.AddRange(_connectedClients.Where(ws => ws.State == WebSocketState.Open));
}
var tasks = clientsCopy.Select(client => SendMessageAsync(client, message));
await Task.WhenAll(tasks);
Console.WriteLine($"广播消息给 {clientsCopy.Count} 个客户端: {message}");
}
public void Stop()
{
_isRunning = false;
_httpListener?.Stop();
lock (_clientsLock)
{
foreach (var client in _connectedClients.ToList())
{
if (client.State == WebSocketState.Open)
{
client.CloseAsync(WebSocketCloseStatus.NormalClosure, "服务器关闭", CancellationToken.None);
}
}
_connectedClients.Clear();
}
Console.WriteLine("WebSocket服务器已停止");
}
}
WebSocket客户端
// WebSocket客户端
public class WebSocketClient
{
private ClientWebSocket _webSocket;
private CancellationTokenSource _cancellationTokenSource;
public event Action<string> MessageReceived;
public event Action Connected;
public event Action Disconnected;
public async Task<bool> ConnectAsync(string uri)
{
try
{
_webSocket = new ClientWebSocket();
_cancellationTokenSource = new CancellationTokenSource();
await _webSocket.ConnectAsync(new Uri(uri), _cancellationTokenSource.Token);
Connected?.Invoke();
Console.WriteLine($"WebSocket客户端已连接到: {uri}");
// 开始接收消息
_ = Task.Run(ReceiveMessagesAsync);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"WebSocket连接失败: {ex.Message}");
return false;
}
}
private async Task ReceiveMessagesAsync()
{
var buffer = new byte[4096];
try
{
while (_webSocket.State == WebSocketState.Open && !_cancellationTokenSource.Token.IsCancellationRequested)
{
var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), _cancellationTokenSource.Token);
if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
MessageReceived?.Invoke(message);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
break;
}
}
}
catch (OperationCanceledException)
{
// 正常取消
}
catch (Exception ex)
{
Console.WriteLine($"接收WebSocket消息时出错: {ex.Message}");
}
finally
{
Disconnected?.Invoke();
}
}
public async Task<bool> SendMessageAsync(string message)
{
if (_webSocket.State != WebSocketState.Open)
{
Console.WriteLine("WebSocket未连接");
return false;
}
try
{
var messageBytes = Encoding.UTF8.GetBytes(message);
await _webSocket.SendAsync(
new ArraySegment<byte>(messageBytes),
WebSocketMessageType.Text,
true,
_cancellationTokenSource.Token);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"发送WebSocket消息失败: {ex.Message}");
return false;
}
}
public async Task DisconnectAsync()
{
if (_webSocket.State == WebSocketState.Open)
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "客户端断开", CancellationToken.None);
}
_cancellationTokenSource?.Cancel();
_webSocket?.Dispose();
_cancellationTokenSource?.Dispose();
Console.WriteLine("WebSocket客户端已断开");
}
}
// WebSocket聊天室示例
public class WebSocketChatRoom
{
private readonly WebSocketServer _server;
private readonly Dictionary<WebSocket, string> _clientNames = new();
private readonly object _namesLock = new();
public WebSocketChatRoom()
{
_server = new WebSocketServer();
_server.ClientConnected += OnClientConnected;
_server.ClientDisconnected += OnClientDisconnected;
_server.MessageReceived += OnMessageReceived;
}
public async Task StartAsync(string prefix)
{
await _server.StartAsync(prefix);
}
private void OnClientConnected(WebSocket client)
{
lock (_namesLock)
{
_clientNames[client] = $"用户{_clientNames.Count + 1}";
}
var welcomeMessage = $"{_clientNames[client]} 加入了聊天室";
_server.BroadcastAsync(welcomeMessage);
}
private void OnClientDisconnected(WebSocket client)
{
string clientName;
lock (_namesLock)
{
_clientNames.TryGetValue(client, out clientName);
_clientNames.Remove(client);
}
if (!string.IsNullOrEmpty(clientName))
{
var leaveMessage = $"{clientName} 离开了聊天室";
_server.BroadcastAsync(leaveMessage);
}
}
private void OnMessageReceived(string message, WebSocket sender)
{
string senderName;
lock (_namesLock)
{
_clientNames.TryGetValue(sender, out senderName);
}
var chatMessage = $"{senderName ?? "未知用户"}: {message}";
_server.BroadcastAsync(chatMessage);
}
public void Stop()
{
_server.Stop();
}
}
// WebSocket使用示例
public class WebSocketDemo
{
public static async Task DemoWebSocketServer()
{
var chatRoom = new WebSocketChatRoom();
await chatRoom.StartAsync("http://localhost:8080/");
Console.WriteLine("WebSocket聊天室已启动,访问 ws://localhost:8080/");
Console.WriteLine("按任意键停止服务器...");
Console.ReadKey();
chatRoom.Stop();
}
public static async Task DemoWebSocketClient()
{
var client = new WebSocketClient();
client.MessageReceived += message => Console.WriteLine($"收到: {message}");
client.Connected += () => Console.WriteLine("已连接到WebSocket服务器");
client.Disconnected += () => Console.WriteLine("与WebSocket服务器断开连接");
if (await client.ConnectAsync("ws://localhost:8080/"))
{
// 发送消息
await client.SendMessageAsync("Hello WebSocket!");
await client.SendMessageAsync("How is everyone?");
await Task.Delay(5000);
await client.DisconnectAsync();
}
}
}
17.5 网络编程最佳实践
连接池和资源管理
using System.Collections.Concurrent;
using System.Net.Sockets;
// TCP连接池
public class TcpConnectionPool : IDisposable
{
private readonly ConcurrentQueue<TcpClient> _availableConnections = new();
private readonly ConcurrentDictionary<TcpClient, DateTime> _activeConnections = new();
private readonly string _serverAddress;
private readonly int _serverPort;
private readonly int _maxConnections;
private readonly TimeSpan _connectionTimeout;
private readonly Timer _cleanupTimer;
private int _currentConnections;
public TcpConnectionPool(string serverAddress, int serverPort, int maxConnections = 10, TimeSpan connectionTimeout = default)
{
_serverAddress = serverAddress;
_serverPort = serverPort;
_maxConnections = maxConnections;
_connectionTimeout = connectionTimeout == default ? TimeSpan.FromMinutes(5) : connectionTimeout;
// 定期清理过期连接
_cleanupTimer = new Timer(CleanupExpiredConnections, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
public async Task<TcpClient> GetConnectionAsync()
{
// 尝试从池中获取可用连接
if (_availableConnections.TryDequeue(out var connection) && connection.Connected)
{
_activeConnections[connection] = DateTime.UtcNow;
return connection;
}
// 创建新连接
if (Interlocked.Read(ref _currentConnections) < _maxConnections)
{
try
{
var newConnection = new TcpClient();
await newConnection.ConnectAsync(_serverAddress, _serverPort);
Interlocked.Increment(ref _currentConnections);
_activeConnections[newConnection] = DateTime.UtcNow;
return newConnection;
}
catch (Exception ex)
{
Console.WriteLine($"创建连接失败: {ex.Message}");
throw;
}
}
throw new InvalidOperationException("连接池已满,无法创建新连接");
}
public void ReturnConnection(TcpClient connection)
{
if (connection != null && connection.Connected)
{
_activeConnections.TryRemove(connection, out _);
_availableConnections.Enqueue(connection);
}
else
{
// 连接已断开,减少计数
if (connection != null)
{
_activeConnections.TryRemove(connection, out _);
connection.Close();
Interlocked.Decrement(ref _currentConnections);
}
}
}
private void CleanupExpiredConnections(object state)
{
var expiredTime = DateTime.UtcNow - _connectionTimeout;
var expiredConnections = new List<TcpClient>();
foreach (var kvp in _activeConnections)
{
if (kvp.Value < expiredTime)
{
expiredConnections.Add(kvp.Key);
}
}
foreach (var connection in expiredConnections)
{
_activeConnections.TryRemove(connection, out _);
connection.Close();
Interlocked.Decrement(ref _currentConnections);
}
Console.WriteLine($"清理了 {expiredConnections.Count} 个过期连接,当前连接数: {_currentConnections}");
}
public void Dispose()
{
_cleanupTimer?.Dispose();
// 关闭所有连接
while (_availableConnections.TryDequeue(out var connection))
{
connection.Close();
}
foreach (var connection in _activeConnections.Keys)
{
connection.Close();
}
_activeConnections.Clear();
}
}
网络安全和加密
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
// SSL/TLS安全通信
public class SecureTcpClient
{
private TcpClient _tcpClient;
private SslStream _sslStream;
private readonly string _serverName;
public SecureTcpClient(string serverName)
{
_serverName = serverName;
}
public async Task<bool> ConnectAsync(string serverAddress, int port)
{
try
{
_tcpClient = new TcpClient();
await _tcpClient.ConnectAsync(serverAddress, port);
// 创建SSL流
_sslStream = new SslStream(
_tcpClient.GetStream(),
false,
ValidateServerCertificate,
null);
// 进行SSL握手
await _sslStream.AuthenticateAsClientAsync(_serverName);
Console.WriteLine($"SSL连接建立成功");
Console.WriteLine($"加密算法: {_sslStream.CipherAlgorithm}");
Console.WriteLine($"哈希算法: {_sslStream.HashAlgorithm}");
Console.WriteLine($"密钥交换算法: {_sslStream.KeyExchangeAlgorithm}");
Console.WriteLine($"协议版本: {_sslStream.SslProtocol}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"SSL连接失败: {ex.Message}");
return false;
}
}
private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine($"SSL证书验证错误: {sslPolicyErrors}");
// 在生产环境中,应该严格验证证书
// 这里为了演示目的,允许自签名证书
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
{
Console.WriteLine("警告: 接受了证书链错误");
return true;
}
return false;
}
public async Task<bool> SendMessageAsync(string message)
{
if (_sslStream == null || !_sslStream.IsAuthenticated)
{
Console.WriteLine("SSL连接未建立");
return false;
}
try
{
var messageBytes = Encoding.UTF8.GetBytes(message);
await _sslStream.WriteAsync(messageBytes, 0, messageBytes.Length);
await _sslStream.FlushAsync();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"发送SSL消息失败: {ex.Message}");
return false;
}
}
public async Task<string> ReceiveMessageAsync()
{
if (_sslStream == null || !_sslStream.IsAuthenticated)
{
Console.WriteLine("SSL连接未建立");
return null;
}
try
{
var buffer = new byte[4096];
var bytesRead = await _sslStream.ReadAsync(buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer, 0, bytesRead);
}
catch (Exception ex)
{
Console.WriteLine($"接收SSL消息失败: {ex.Message}");
return null;
}
}
public void Disconnect()
{
_sslStream?.Close();
_tcpClient?.Close();
Console.WriteLine("SSL连接已关闭");
}
}
网络性能监控
using System.Diagnostics;
using System.Net.NetworkInformation;
// 网络性能监控器
public class NetworkPerformanceMonitor
{
private readonly Dictionary<string, List<long>> _latencyHistory = new();
private readonly Dictionary<string, long> _totalBytesSent = new();
private readonly Dictionary<string, long> _totalBytesReceived = new();
private readonly object _statsLock = new();
// 测量网络延迟
public async Task<long> MeasureLatencyAsync(string hostName, int timeout = 5000)
{
try
{
using var ping = new Ping();
var reply = await ping.SendPingAsync(hostName, timeout);
if (reply.Status == IPStatus.Success)
{
var latency = reply.RoundtripTime;
lock (_statsLock)
{
if (!_latencyHistory.ContainsKey(hostName))
_latencyHistory[hostName] = new List<long>();
_latencyHistory[hostName].Add(latency);
// 保持最近100次的记录
if (_latencyHistory[hostName].Count > 100)
_latencyHistory[hostName].RemoveAt(0);
}
return latency;
}
else
{
Console.WriteLine($"Ping {hostName} 失败: {reply.Status}");
return -1;
}
}
catch (Exception ex)
{
Console.WriteLine($"测量延迟失败: {ex.Message}");
return -1;
}
}
// 记录数据传输
public void RecordDataTransfer(string endpoint, long bytesSent, long bytesReceived)
{
lock (_statsLock)
{
if (!_totalBytesSent.ContainsKey(endpoint))
_totalBytesSent[endpoint] = 0;
if (!_totalBytesReceived.ContainsKey(endpoint))
_totalBytesReceived[endpoint] = 0;
_totalBytesSent[endpoint] += bytesSent;
_totalBytesReceived[endpoint] += bytesReceived;
}
}
// 获取延迟统计
public NetworkLatencyStats GetLatencyStats(string hostName)
{
lock (_statsLock)
{
if (!_latencyHistory.ContainsKey(hostName) || _latencyHistory[hostName].Count == 0)
return null;
var latencies = _latencyHistory[hostName];
return new NetworkLatencyStats
{
HostName = hostName,
MinLatency = latencies.Min(),
MaxLatency = latencies.Max(),
AverageLatency = latencies.Average(),
SampleCount = latencies.Count
};
}
}
// 获取传输统计
public NetworkTransferStats GetTransferStats(string endpoint)
{
lock (_statsLock)
{
return new NetworkTransferStats
{
Endpoint = endpoint,
TotalBytesSent = _totalBytesSent.GetValueOrDefault(endpoint, 0),
TotalBytesReceived = _totalBytesReceived.GetValueOrDefault(endpoint, 0)
};
}
}
// 获取网络接口信息
public List<NetworkInterfaceInfo> GetNetworkInterfaces()
{
var interfaces = new List<NetworkInterfaceInfo>();
foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
{
if (ni.OperationalStatus == OperationalStatus.Up)
{
var stats = ni.GetIPv4Statistics();
interfaces.Add(new NetworkInterfaceInfo
{
Name = ni.Name,
Description = ni.Description,
Type = ni.NetworkInterfaceType.ToString(),
Speed = ni.Speed,
BytesSent = stats.BytesSent,
BytesReceived = stats.BytesReceived,
PacketsSent = stats.UnicastPacketsSent,
PacketsReceived = stats.UnicastPacketsReceived
});
}
}
return interfaces;
}
}
// 网络统计数据模型
public class NetworkLatencyStats
{
public string HostName { get; set; }
public long MinLatency { get; set; }
public long MaxLatency { get; set; }
public double AverageLatency { get; set; }
public int SampleCount { get; set; }
}
public class NetworkTransferStats
{
public string Endpoint { get; set; }
public long TotalBytesSent { get; set; }
public long TotalBytesReceived { get; set; }
public string FormattedBytesSent => FormatBytes(TotalBytesSent);
public string FormattedBytesReceived => FormatBytes(TotalBytesReceived);
private string FormatBytes(long bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
int counter = 0;
decimal number = bytes;
while (Math.Round(number / 1024) >= 1)
{
number /= 1024;
counter++;
}
return $"{number:N1} {suffixes[counter]}";
}
}
public class NetworkInterfaceInfo
{
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public long Speed { get; set; }
public long BytesSent { get; set; }
public long BytesReceived { get; set; }
public long PacketsSent { get; set; }
public long PacketsReceived { get; set; }
}
网络编程实践练习
练习1:HTTP API客户端
// RESTful API客户端
public class ApiClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
private readonly NetworkPerformanceMonitor _monitor;
public ApiClient(string baseUrl)
{
_baseUrl = baseUrl.TrimEnd('/');
_httpClient = new HttpClient();
_monitor = new NetworkPerformanceMonitor();
_httpClient.DefaultRequestHeaders.Add("User-Agent", "ApiClient/1.0");
}
// 通用API请求方法
public async Task<ApiResponse<T>> SendRequestAsync<T>(string endpoint, HttpMethod method, object data = null, Dictionary<string, string> headers = null)
{
var url = $"{_baseUrl}/{endpoint.TrimStart('/')}";
var stopwatch = Stopwatch.StartNew();
try
{
using var request = new HttpRequestMessage(method, url);
// 添加自定义头
if (headers != null)
{
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
}
// 添加请求体
if (data != null && (method == HttpMethod.Post || method == HttpMethod.Put || method == HttpMethod.Patch))
{
var json = JsonSerializer.Serialize(data);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
}
var response = await _httpClient.SendAsync(request);
stopwatch.Stop();
var responseContent = await response.Content.ReadAsStringAsync();
// 记录性能数据
var requestSize = request.Content?.Headers.ContentLength ?? 0;
var responseSize = responseContent.Length;
_monitor.RecordDataTransfer(url, requestSize, responseSize);
var result = new ApiResponse<T>
{
IsSuccess = response.IsSuccessStatusCode,
StatusCode = (int)response.StatusCode,
ResponseTime = stopwatch.ElapsedMilliseconds,
Headers = response.Headers.ToDictionary(h => h.Key, h => string.Join(",", h.Value))
};
if (response.IsSuccessStatusCode)
{
if (typeof(T) == typeof(string))
{
result.Data = (T)(object)responseContent;
}
else
{
result.Data = JsonSerializer.Deserialize<T>(responseContent);
}
}
else
{
result.ErrorMessage = responseContent;
}
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
return new ApiResponse<T>
{
IsSuccess = false,
ErrorMessage = ex.Message,
ResponseTime = stopwatch.ElapsedMilliseconds
};
}
}
// GET请求
public async Task<ApiResponse<T>> GetAsync<T>(string endpoint, Dictionary<string, string> headers = null)
{
return await SendRequestAsync<T>(endpoint, HttpMethod.Get, null, headers);
}
// POST请求
public async Task<ApiResponse<T>> PostAsync<T>(string endpoint, object data, Dictionary<string, string> headers = null)
{
return await SendRequestAsync<T>(endpoint, HttpMethod.Post, data, headers);
}
// PUT请求
public async Task<ApiResponse<T>> PutAsync<T>(string endpoint, object data, Dictionary<string, string> headers = null)
{
return await SendRequestAsync<T>(endpoint, HttpMethod.Put, data, headers);
}
// DELETE请求
public async Task<ApiResponse<T>> DeleteAsync<T>(string endpoint, Dictionary<string, string> headers = null)
{
return await SendRequestAsync<T>(endpoint, HttpMethod.Delete, null, headers);
}
// 获取性能统计
public NetworkTransferStats GetTransferStats(string endpoint)
{
return _monitor.GetTransferStats(endpoint);
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
// API响应模型
public class ApiResponse<T>
{
public bool IsSuccess { get; set; }
public int StatusCode { get; set; }
public T Data { get; set; }
public string ErrorMessage { get; set; }
public long ResponseTime { get; set; }
public Dictionary<string, string> Headers { get; set; } = new();
}
// 使用示例
public class ApiClientDemo
{
public static async Task DemoApiClient()
{
var client = new ApiClient("https://jsonplaceholder.typicode.com");
// GET请求
var getResponse = await client.GetAsync<dynamic>("/posts/1");
if (getResponse.IsSuccess)
{
Console.WriteLine($"GET成功,响应时间: {getResponse.ResponseTime}ms");
Console.WriteLine($"数据: {getResponse.Data}");
}
// POST请求
var postData = new { title = "测试标题", body = "测试内容", userId = 1 };
var postResponse = await client.PostAsync<dynamic>("/posts", postData);
if (postResponse.IsSuccess)
{
Console.WriteLine($"POST成功,响应时间: {postResponse.ResponseTime}ms");
Console.WriteLine($"创建的数据: {postResponse.Data}");
}
// 获取传输统计
var stats = client.GetTransferStats("https://jsonplaceholder.typicode.com/posts/1");
Console.WriteLine($"传输统计 - 发送: {stats.FormattedBytesSent}, 接收: {stats.FormattedBytesReceived}");
client.Dispose();
}
}
练习2:实时聊天系统
// 聊天服务器
public class ChatServer
{
private readonly TcpListener _listener;
private readonly List<ChatClient> _clients = new();
private readonly object _clientsLock = new();
private bool _isRunning;
public ChatServer(int port)
{
_listener = new TcpListener(IPAddress.Any, port);
}
public async Task StartAsync()
{
_listener.Start();
_isRunning = true;
Console.WriteLine($"聊天服务器启动,监听端口: {((IPEndPoint)_listener.LocalEndpoint).Port}");
while (_isRunning)
{
try
{
var tcpClient = await _listener.AcceptTcpClientAsync();
var chatClient = new ChatClient(tcpClient, this);
lock (_clientsLock)
{
_clients.Add(chatClient);
}
_ = Task.Run(() => chatClient.HandleAsync());
Console.WriteLine($"新客户端连接: {tcpClient.Client.RemoteEndPoint}");
}
catch (ObjectDisposedException)
{
break;
}
catch (Exception ex)
{
Console.WriteLine($"接受连接时出错: {ex.Message}");
}
}
}
public void BroadcastMessage(string message, ChatClient sender = null)
{
lock (_clientsLock)
{
var disconnectedClients = new List<ChatClient>();
foreach (var client in _clients)
{
if (client != sender)
{
if (!client.SendMessage(message))
{
disconnectedClients.Add(client);
}
}
}
// 移除断开连接的客户端
foreach (var client in disconnectedClients)
{
_clients.Remove(client);
Console.WriteLine($"移除断开连接的客户端: {client.RemoteEndPoint}");
}
}
}
public void RemoveClient(ChatClient client)
{
lock (_clientsLock)
{
_clients.Remove(client);
}
}
public int GetClientCount()
{
lock (_clientsLock)
{
return _clients.Count;
}
}
public void Stop()
{
_isRunning = false;
_listener?.Stop();
lock (_clientsLock)
{
foreach (var client in _clients)
{
client.Disconnect();
}
_clients.Clear();
}
Console.WriteLine("聊天服务器已停止");
}
}
// 聊天客户端(服务器端)
public class ChatClient
{
private readonly TcpClient _tcpClient;
private readonly NetworkStream _stream;
private readonly ChatServer _server;
private readonly StreamReader _reader;
private readonly StreamWriter _writer;
public string RemoteEndPoint { get; }
public string Username { get; private set; }
public ChatClient(TcpClient tcpClient, ChatServer server)
{
_tcpClient = tcpClient;
_server = server;
_stream = tcpClient.GetStream();
_reader = new StreamReader(_stream, Encoding.UTF8);
_writer = new StreamWriter(_stream, Encoding.UTF8) { AutoFlush = true };
RemoteEndPoint = tcpClient.Client.RemoteEndPoint?.ToString();
}
public async Task HandleAsync()
{
try
{
// 获取用户名
await _writer.WriteLineAsync("请输入您的用户名:");
Username = await _reader.ReadLineAsync();
if (string.IsNullOrWhiteSpace(Username))
{
Username = $"用户{RemoteEndPoint}";
}
await _writer.WriteLineAsync($"欢迎 {Username}! 当前在线用户: {_server.GetClientCount()}");
_server.BroadcastMessage($"[系统] {Username} 加入了聊天室", this);
string message;
while ((message = await _reader.ReadLineAsync()) != null)
{
if (message.ToLower() == "/quit")
{
break;
}
else if (message.ToLower() == "/users")
{
await _writer.WriteLineAsync($"当前在线用户数: {_server.GetClientCount()}");
}
else if (message.StartsWith("/"))
{
await _writer.WriteLineAsync("未知命令。可用命令: /quit, /users");
}
else if (!string.IsNullOrWhiteSpace(message))
{
var chatMessage = $"[{DateTime.Now:HH:mm:ss}] {Username}: {message}";
_server.BroadcastMessage(chatMessage, this);
Console.WriteLine(chatMessage);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"处理客户端 {RemoteEndPoint} 时出错: {ex.Message}");
}
finally
{
_server.BroadcastMessage($"[系统] {Username} 离开了聊天室", this);
_server.RemoveClient(this);
Disconnect();
}
}
public bool SendMessage(string message)
{
try
{
_writer.WriteLine(message);
return true;
}
catch
{
return false;
}
}
public void Disconnect()
{
try
{
_reader?.Close();
_writer?.Close();
_stream?.Close();
_tcpClient?.Close();
}
catch (Exception ex)
{
Console.WriteLine($"断开连接时出错: {ex.Message}");
}
}
}
// 聊天客户端(客户端)
public class ChatClientApp
{
private TcpClient _tcpClient;
private NetworkStream _stream;
private StreamReader _reader;
private StreamWriter _writer;
private bool _isConnected;
public async Task<bool> ConnectAsync(string serverAddress, int port)
{
try
{
_tcpClient = new TcpClient();
await _tcpClient.ConnectAsync(serverAddress, port);
_stream = _tcpClient.GetStream();
_reader = new StreamReader(_stream, Encoding.UTF8);
_writer = new StreamWriter(_stream, Encoding.UTF8) { AutoFlush = true };
_isConnected = true;
Console.WriteLine($"已连接到聊天服务器 {serverAddress}:{port}");
// 启动接收消息的任务
_ = Task.Run(ReceiveMessagesAsync);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"连接失败: {ex.Message}");
return false;
}
}
private async Task ReceiveMessagesAsync()
{
try
{
string message;
while (_isConnected && (message = await _reader.ReadLineAsync()) != null)
{
Console.WriteLine(message);
}
}
catch (Exception ex)
{
if (_isConnected)
{
Console.WriteLine($"接收消息时出错: {ex.Message}");
}
}
}
public async Task SendMessageAsync(string message)
{
if (_isConnected && _writer != null)
{
try
{
await _writer.WriteLineAsync(message);
}
catch (Exception ex)
{
Console.WriteLine($"发送消息失败: {ex.Message}");
}
}
}
public void Disconnect()
{
_isConnected = false;
try
{
_reader?.Close();
_writer?.Close();
_stream?.Close();
_tcpClient?.Close();
}
catch (Exception ex)
{
Console.WriteLine($"断开连接时出错: {ex.Message}");
}
Console.WriteLine("已断开连接");
}
}
// 聊天系统演示
public class ChatSystemDemo
{
public static async Task DemoServer()
{
var server = new ChatServer(8080);
// 启动服务器
var serverTask = Task.Run(() => server.StartAsync());
Console.WriteLine("按任意键停止服务器...");
Console.ReadKey();
server.Stop();
}
public static async Task DemoClient()
{
var client = new ChatClientApp();
if (await client.ConnectAsync("localhost", 8080))
{
Console.WriteLine("输入消息发送,输入 /quit 退出:");
string input;
while ((input = Console.ReadLine()) != "/quit")
{
await client.SendMessageAsync(input);
}
await client.SendMessageAsync("/quit");
client.Disconnect();
}
}
}
17.6 本章总结
在本章中,我们深入学习了C#网络编程的各个方面:
核心概念
- HTTP客户端编程:使用
HttpClient
进行RESTful API调用 - TCP网络编程:使用
TcpListener
和TcpClient
进行可靠的网络通信 - UDP网络编程:使用
UdpClient
进行快速的无连接通信 - WebSocket编程:实现实时双向通信
高级技术
- 连接池管理:优化网络资源使用和性能
- SSL/TLS安全通信:保护数据传输安全
- 网络性能监控:监测延迟、吞吐量和网络状态
- 异步编程模式:提高网络应用的并发性能
最佳实践
- 资源管理:正确释放网络资源,避免内存泄漏
- 错误处理:优雅处理网络异常和连接失败
- 性能优化:使用连接池、缓冲和异步操作
- 安全考虑:验证证书、加密通信、防止攻击
实际应用
- HTTP API客户端:构建可复用的RESTful API客户端
- 实时聊天系统:实现多用户实时通信
- 文件传输:安全高效的文件上传下载
- 网络监控:实时监测网络性能和状态
重要技能
- 掌握各种网络协议的使用场景和特点
- 能够设计和实现高性能的网络应用
- 理解网络安全的重要性并能实施安全措施
- 具备网络问题诊断和性能优化的能力
网络编程是现代应用开发的重要技能,通过本章的学习,你应该能够: - 开发各种类型的网络客户端和服务器 - 处理复杂的网络通信场景 - 优化网络应用的性能和安全性 - 构建可扩展的分布式系统
下一章我们将学习数据库编程,探讨如何在C#中与各种数据库进行交互,包括关系型数据库和NoSQL数据库的操作。
using System.Net;
using System.Net.Http.Headers;
// 高级HTTP客户端
public class AdvancedHttpClient
{
private readonly HttpClient _httpClient;
public AdvancedHttpClient()
{
var handler = new HttpClientHandler()
{
// 配置代理
Proxy = new WebProxy("http://proxy.example.com:8080"),
UseProxy = true,
// 配置Cookie
CookieContainer = new CookieContainer(),
UseCookies = true,
// SSL配置
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
};
_httpClient = new HttpClient(handler);
// 设置默认请求头
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.DefaultRequestHeaders.Add("User-Agent", "AdvancedHttpClient/1.0");
}
// 带认证的请求
public async Task<string> GetWithAuthAsync(string url, string token)
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// 基本认证
public async Task<string> GetWithBasicAuthAsync(string url, string username, string password)
{
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}"));
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// 自定义请求头
public async Task<string> GetWithCustomHeadersAsync(string url, Dictionary<string, string> headers)
{
using var request = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// 重试机制
public async Task<string> GetWithRetryAsync(string url, int maxRetries = 3, TimeSpan delay = default)
{
if (delay == default)
delay = TimeSpan.FromSeconds(1);
for (int i = 0; i <= maxRetries; i++)
{
try
{
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException) when (i < maxRetries)
{
Console.WriteLine($"请求失败,{delay.TotalSeconds}秒后重试... (尝试 {i + 1}/{maxRetries + 1})");
await Task.Delay(delay);
delay = TimeSpan.FromMilliseconds(delay.TotalMilliseconds * 2); // 指数退避
}
}
throw new HttpRequestException($"在{maxRetries + 1}次尝试后请求仍然失败");
}
// 并发请求
public async Task<List<string>> GetMultipleAsync(IEnumerable<string> urls)
{
var tasks = urls.Select(url => _httpClient.GetStringAsync(url));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
// 流式读取大响应
public async Task ProcessLargeResponseAsync(string url, Func<string, Task> lineProcessor)
{
using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
await lineProcessor(line);
}
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
17.2 TCP网络编程
TCP服务器
using System.Net;
using System.Net.Sockets;
using System.Text;
// TCP服务器
public class TcpServer
{
private TcpListener _listener;
private bool _isRunning;
private readonly List<TcpClient> _clients = new();
private readonly object _clientsLock = new();
public event Action<string> MessageReceived;
public event Action<string> ClientConnected;
public event Action<string> ClientDisconnected;
public async Task StartAsync(IPAddress ipAddress, int port)
{
_listener = new TcpListener(ipAddress, port);
_listener.Start();
_isRunning = true;
Console.WriteLine($"TCP服务器启动在 {ipAddress}:{port}");
// 接受客户端连接
_ = Task.Run(AcceptClientsAsync);
}
private async Task AcceptClientsAsync()
{
while (_isRunning)
{
try
{
var tcpClient = await _listener.AcceptTcpClientAsync();
var clientEndpoint = tcpClient.Client.RemoteEndPoint?.ToString();
lock (_clientsLock)
{
_clients.Add(tcpClient);
}
ClientConnected?.Invoke(clientEndpoint);
Console.WriteLine($"客户端连接: {clientEndpoint}");
// 为每个客户端启动处理任务
_ = Task.Run(() => HandleClientAsync(tcpClient));
}
catch (ObjectDisposedException)
{
// 服务器已停止
break;
}
catch (Exception ex)
{
Console.WriteLine($"接受客户端连接时出错: {ex.Message}");
}
}
}
private async Task HandleClientAsync(TcpClient client)
{
var clientEndpoint = client.Client.RemoteEndPoint?.ToString();
var stream = client.GetStream();
var buffer = new byte[4096];
try
{
while (client.Connected && _isRunning)
{
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
// 客户端断开连接
break;
}
var message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
MessageReceived?.Invoke($"{clientEndpoint}: {message}");
// 回显消息
var response = $"服务器收到: {message}";
var responseBytes = Encoding.UTF8.GetBytes(response);
await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
}
}
catch (Exception ex)
{
Console.WriteLine($"处理客户端 {clientEndpoint} 时出错: {ex.Message}");
}
finally
{
lock (_clientsLock)
{
_clients.Remove(client);
}
ClientDisconnected?.Invoke(clientEndpoint);
Console.WriteLine($"客户端断开: {clientEndpoint}");
client.Close();
}
}
// 广播消息给所有客户端
public async Task BroadcastAsync(string message)
{
var messageBytes = Encoding.UTF8.GetBytes(message);
var clientsCopy = new List<TcpClient>();
lock (_clientsLock)
{
clientsCopy.AddRange(_clients);
}
var tasks = clientsCopy.Select(async client =>
{
try
{
if (client.Connected)
{
var stream = client.GetStream();
await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
}
}
catch (Exception ex)
{
Console.WriteLine($"广播消息时出错: {ex.Message}");
}
});
await Task.WhenAll(tasks);
}
public void Stop()
{
_isRunning = false;
_listener?.Stop();
lock (_clientsLock)
{
foreach (var client in _clients)
{
client.Close();
}
_clients.Clear();
}
Console.WriteLine("TCP服务器已停止");
}
}
TCP客户端
// TCP客户端
public class TcpClientWrapper
{
private TcpClient _client;
private NetworkStream _stream;
private bool _isConnected;
public event Action<string> MessageReceived;
public event Action Connected;
public event Action Disconnected;
public async Task<bool> ConnectAsync(string serverAddress, int port)
{
try
{
_client = new TcpClient();
await _client.ConnectAsync(serverAddress, port);
_stream = _client.GetStream();
_isConnected = true;
Connected?.Invoke();
Console.WriteLine($"连接到服务器 {serverAddress}:{port}");
// 启动接收消息的任务
_ = Task.Run(ReceiveMessagesAsync);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"连接失败: {ex.Message}");
return false;
}
}
private async Task ReceiveMessagesAsync()
{
var buffer = new byte[4096];
try
{
while (_isConnected && _client.Connected)
{
var bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
// 服务器断开连接
break;
}
var message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
MessageReceived?.Invoke(message);
}
}
catch (Exception ex)
{
Console.WriteLine($"接收消息时出错: {ex.Message}");
}
finally
{
_isConnected = false;
Disconnected?.Invoke();
}
}
public async Task<bool> SendMessageAsync(string message)
{
if (!_isConnected || !_client.Connected)
{
Console.WriteLine("未连接到服务器");
return false;
}
try
{
var messageBytes = Encoding.UTF8.GetBytes(message);
await _stream.WriteAsync(messageBytes, 0, messageBytes.Length);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"发送消息失败: {ex.Message}");
return false;
}
}
public void Disconnect()
{
_isConnected = false;
_stream?.Close();
_client?.Close();
Console.WriteLine("已断开连接");
}
}
// TCP通信示例
public class TcpDemo
{
public static async Task DemoTcpServer()
{
var server = new TcpServer();
server.MessageReceived += message => Console.WriteLine($"收到消息: {message}");
server.ClientConnected += client => Console.WriteLine($"客户端连接: {client}");
server.ClientDisconnected += client => Console.WriteLine($"客户端断开: {client}");
await server.StartAsync(IPAddress.Any, 8080);
// 模拟广播消息
await Task.Delay(5000);
await server.BroadcastAsync("服务器广播消息");
Console.WriteLine("按任意键停止服务器...");
Console.ReadKey();
server.Stop();
}
public static async Task DemoTcpClient()
{
var client = new TcpClientWrapper();
client.MessageReceived += message => Console.WriteLine($"收到: {message}");
client.Connected += () => Console.WriteLine("已连接到服务器");
client.Disconnected += () => Console.WriteLine("与服务器断开连接");
if (await client.ConnectAsync("localhost", 8080))
{
// 发送消息
await client.SendMessageAsync("Hello from client!");
await client.SendMessageAsync("How are you?");
Console.WriteLine("按任意键断开连接...");
Console.ReadKey();
client.Disconnect();
}
}
}