学习目标

  • 掌握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网络编程:使用TcpListenerTcpClient进行可靠的网络通信
  • 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();
        }
    }
}