C# .NET Framework 4.0 网络编程完全指南
文档主要内容包括:
文件传输协议部分
FTP:使用.NET内置的FtpWebRequest类实现文件上传、下载和目录列表
SFTP/SCP:通过SSH.NET库实现安全文件传输(需要NuGet安装)
TFTP:自定义实现的简单文件传输协议
远程终端协议部分
Telnet:基于TcpClient的明文终端协议实现
SSH:使用SSH.NET库实现安全Shell连接和命令执行
Socket编程部分
原始Socket:展示了TCP服务器/客户端的完整实现,包括同步和异步操作
TcpClient类:使用高级封装类简化TCP通信
UDP编程:包括单播、广播和组播的实现
高级特性
连接池管理:提高性能的连接复用机制
心跳检测:保持连接活跃和故障检测
协议封装:自定义通信协议的设计和实现
特别说明:
所有代码都严格遵循.NET Framework 4.0标准,避免了字符串插值($)、null条件运算符(?.)等C# 6.0后的新语法
第三方库依赖:SFTP、SCP和SSH功能需要安装SSH.NET库(通过NuGet:Install-Package SSH.NET -Version 2016.1.0)
每个示例都包含:
完整的错误处理
资源释放机制
详细的中文注释
同步和异步操作示例
实用性强:代码可以直接复制使用,只需根据实际情况调整服务器地址、端口等参数
一、文件传输协议
1. FTP (File Transfer Protocol)
概述
FTP是用于在网络上进行文件传输的标准协议,工作在TCP/IP协议族的应用层,使用21端口进行控制连接,20端口进行数据传输。
实现方式
csharp
using System;
using System.IO;
using System.Net;
public class FtpHelper
{
private string ftpServer;
private string userName;
private string password;
public FtpHelper(string server, string user, string pass)
{
this.ftpServer = server;
this.userName = user;
this.password = pass;
}
// 上传文件
public bool UploadFile(string localFile, string remoteFile)
{
try
{
FileInfo fileInfo = new FileInfo(localFile);
string uri = "ftp://" + ftpServer + "/" + remoteFile;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(userName, password);
request.KeepAlive = false;
request.UseBinary = true;
request.ContentLength = fileInfo.Length;
byte[] buffer = new byte[2048];
int contentLen;
using (FileStream fs = fileInfo.OpenRead())
{
using (Stream strm = request.GetRequestStream())
{
contentLen = fs.Read(buffer, 0, buffer.Length);
while (contentLen != 0)
{
strm.Write(buffer, 0, contentLen);
contentLen = fs.Read(buffer, 0, buffer.Length);
}
}
}
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
return true;
}
catch (Exception ex)
{
Console.WriteLine("FTP上传失败: " + ex.Message);
return false;
}
}
// 下载文件
public bool DownloadFile(string remoteFile, string localFile)
{
try
{
string uri = "ftp://" + ftpServer + "/" + remoteFile;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(userName, password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
using (FileStream fs = new FileStream(localFile, FileMode.Create))
{
byte[] buffer = new byte[2048];
int read = 0;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
fs.Write(buffer, 0, read);
}
}
responseStream.Close();
response.Close();
return true;
}
catch (Exception ex)
{
Console.WriteLine("FTP下载失败: " + ex.Message);
return false;
}
}
// 列出目录内容
public string[] ListDirectory(string directory)
{
try
{
string uri = "ftp://" + ftpServer + "/" + directory;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(userName, password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string result = reader.ReadToEnd();
reader.Close();
response.Close();
return result.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
}
catch (Exception ex)
{
Console.WriteLine("列出目录失败: " + ex.Message);
return new string[0];
}
}
}
2. SFTP (SSH File Transfer Protocol)
概述
SFTP是基于SSH协议的安全文件传输协议,提供加密的文件传输功能。.NET Framework 4.0原生不支持SFTP,需要使用第三方库如SSH.NET。
使用SSH.NET库实现(需通过NuGet安装)
csharp
// 安装命令: Install-Package SSH.NET -Version 2016.1.0
using Renci.SshNet;
using System;
using System.IO;
public class SftpHelper
{
private string host;
private string username;
private string password;
private int port;
public SftpHelper(string host, string username, string password, int port = 22)
{
this.host = host;
this.username = username;
this.password = password;
this.port = port;
}
// 上传文件
public bool UploadFile(string localPath, string remotePath)
{
try
{
using (SftpClient sftp = new SftpClient(host, port, username, password))
{
sftp.Connect();
using (FileStream fs = new FileStream(localPath, FileMode.Open))
{
sftp.UploadFile(fs, remotePath);
}
sftp.Disconnect();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("SFTP上传失败: " + ex.Message);
return false;
}
}
// 下载文件
public bool DownloadFile(string remotePath, string localPath)
{
try
{
using (SftpClient sftp = new SftpClient(host, port, username, password))
{
sftp.Connect();
using (FileStream fs = new FileStream(localPath, FileMode.Create))
{
sftp.DownloadFile(remotePath, fs);
}
sftp.Disconnect();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("SFTP下载失败: " + ex.Message);
return false;
}
}
}
3. SCP (Secure Copy Protocol)
概述
SCP是基于SSH协议的文件传输协议,用于在网络主机间安全地传输文件。同样需要使用SSH.NET库。
csharp
using Renci.SshNet;
using System;
public class ScpHelper
{
private string host;
private string username;
private string password;
public ScpHelper(string host, string username, string password)
{
this.host = host;
this.username = username;
this.password = password;
}
// 上传文件
public bool UploadFile(string localPath, string remotePath)
{
try
{
using (ScpClient scp = new ScpClient(host, username, password))
{
scp.Connect();
scp.Upload(new System.IO.FileInfo(localPath), remotePath);
scp.Disconnect();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("SCP上传失败: " + ex.Message);
return false;
}
}
// 下载文件
public bool DownloadFile(string remotePath, string localPath)
{
try
{
using (ScpClient scp = new ScpClient(host, username, password))
{
scp.Connect();
scp.Download(remotePath, new System.IO.DirectoryInfo(localPath));
scp.Disconnect();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("SCP下载失败: " + ex.Message);
return false;
}
}
}
4. TFTP (Trivial File Transfer Protocol)
概述
TFTP是一个简化的文件传输协议,基于UDP,通常用于网络设备的固件更新。需要自行实现或使用第三方库。
csharp
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
public class TftpClient
{
private const int TFTP_PORT = 69;
private const int BLOCK_SIZE = 512;
// TFTP操作码
private enum Opcode : ushort
{
RRQ = 1, // 读请求
WRQ = 2, // 写请求
DATA = 3, // 数据包
ACK = 4, // 确认
ERROR = 5 // 错误
}
private string serverAddress;
private UdpClient udpClient;
public TftpClient(string server)
{
this.serverAddress = server;
this.udpClient = new UdpClient();
}
// 下载文件(简化版本)
public bool DownloadFile(string remoteFile, string localFile)
{
try
{
IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse(serverAddress), TFTP_PORT);
// 构建RRQ请求
byte[] request = BuildRequest(Opcode.RRQ, remoteFile, "octet");
udpClient.Send(request, request.Length, serverEP);
using (FileStream fs = new FileStream(localFile, FileMode.Create))
{
ushort blockNumber = 1;
byte[] buffer;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
buffer = udpClient.Receive(ref remoteEP);
if (buffer.Length >= 2)
{
ushort opcode = (ushort)((buffer[0] << 8) | buffer[1]);
if (opcode == (ushort)Opcode.DATA)
{
ushort receivedBlock = (ushort)((buffer[2] << 8) | buffer[3]);
if (receivedBlock == blockNumber)
{
int dataLength = buffer.Length - 4;
fs.Write(buffer, 4, dataLength);
// 发送ACK
byte[] ack = BuildAck(blockNumber);
udpClient.Send(ack, ack.Length, remoteEP);
if (dataLength < BLOCK_SIZE)
{
break; // 传输完成
}
blockNumber++;
}
}
else if (opcode == (ushort)Opcode.ERROR)
{
Console.WriteLine("TFTP错误");
return false;
}
}
}
}
return true;
}
catch (Exception ex)
{
Console.WriteLine("TFTP下载失败: " + ex.Message);
return false;
}
}
private byte[] BuildRequest(Opcode opcode, string filename, string mode)
{
using (MemoryStream ms = new MemoryStream())
{
// 操作码
ms.WriteByte((byte)((ushort)opcode >> 8));
ms.WriteByte((byte)((ushort)opcode & 0xFF));
// 文件名
byte[] filenameBytes = System.Text.Encoding.ASCII.GetBytes(filename);
ms.Write(filenameBytes, 0, filenameBytes.Length);
ms.WriteByte(0);
// 模式
byte[] modeBytes = System.Text.Encoding.ASCII.GetBytes(mode);
ms.Write(modeBytes, 0, modeBytes.Length);
ms.WriteByte(0);
return ms.ToArray();
}
}
private byte[] BuildAck(ushort blockNumber)
{
return new byte[] {
0, (byte)Opcode.ACK,
(byte)(blockNumber >> 8),
(byte)(blockNumber & 0xFF)
};
}
}
二、远程终端协议
1. Telnet
概述
Telnet是一种网络协议,用于通过网络提供双向交互式文本通信。它是不安全的明文协议。
csharp
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class TelnetClient
{
private TcpClient tcpClient;
private NetworkStream stream;
private string host;
private int port;
public TelnetClient(string host, int port = 23)
{
this.host = host;
this.port = port;
}
public bool Connect()
{
try
{
tcpClient = new TcpClient();
tcpClient.Connect(host, port);
stream = tcpClient.GetStream();
return true;
}
catch (Exception ex)
{
Console.WriteLine("Telnet连接失败: " + ex.Message);
return false;
}
}
public void Send(string command)
{
if (stream != null && stream.CanWrite)
{
byte[] data = Encoding.ASCII.GetBytes(command + "\r\n");
stream.Write(data, 0, data.Length);
stream.Flush();
}
}
public string Receive(int timeout = 1000)
{
if (stream != null && stream.CanRead)
{
StringBuilder sb = new StringBuilder();
DateTime startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < timeout)
{
if (stream.DataAvailable)
{
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
sb.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead));
}
else
{
Thread.Sleep(100);
}
}
return sb.ToString();
}
return string.Empty;
}
public void Disconnect()
{
if (stream != null)
{
stream.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
}
// Telnet协商处理(简化版)
private byte[] NegotiateOptions(byte[] data)
{
// IAC (Interpret As Command) = 255
const byte IAC = 255;
const byte DO = 253;
const byte DONT = 254;
const byte WILL = 251;
const byte WONT = 252;
for (int i = 0; i < data.Length; i++)
{
if (data[i] == IAC && i + 2 < data.Length)
{
byte command = data[i + 1];
byte option = data[i + 2];
// 简单的协商响应
byte[] response = new byte[3];
response[0] = IAC;
if (command == DO)
{
response[1] = WONT; // 拒绝所有选项
}
else if (command == WILL)
{
response[1] = DONT; // 拒绝所有选项
}
response[2] = option;
if (stream != null && stream.CanWrite)
{
stream.Write(response, 0, 3);
}
i += 2; // 跳过已处理的字节
}
}
return data;
}
}
2. SSH (Secure Shell)
概述
SSH是一种加密的网络协议,用于在不安全的网络上安全地运行网络服务。使用SSH.NET库实现。
csharp
using Renci.SshNet;
using System;
public class SshHelper
{
private string host;
private string username;
private string password;
private int port;
private SshClient sshClient;
public SshHelper(string host, string username, string password, int port = 22)
{
this.host = host;
this.username = username;
this.password = password;
this.port = port;
}
// 连接到SSH服务器
public bool Connect()
{
try
{
sshClient = new SshClient(host, port, username, password);
sshClient.Connect();
return sshClient.IsConnected;
}
catch (Exception ex)
{
Console.WriteLine("SSH连接失败: " + ex.Message);
return false;
}
}
// 执行单个命令
public string ExecuteCommand(string command)
{
if (sshClient != null && sshClient.IsConnected)
{
try
{
SshCommand cmd = sshClient.CreateCommand(command);
string result = cmd.Execute();
if (!string.IsNullOrEmpty(cmd.Error))
{
Console.WriteLine("命令错误: " + cmd.Error);
}
return result;
}
catch (Exception ex)
{
Console.WriteLine("执行命令失败: " + ex.Message);
return string.Empty;
}
}
return string.Empty;
}
// 创建Shell会话(交互式)
public void CreateShellSession()
{
if (sshClient != null && sshClient.IsConnected)
{
try
{
var shell = sshClient.CreateShellStream("xterm", 80, 24, 800, 600, 1024);
// 读取欢迎信息
string line = shell.ReadLine();
while (!string.IsNullOrEmpty(line))
{
Console.WriteLine(line);
line = shell.ReadLine();
}
// 交互式会话
while (true)
{
Console.Write("ssh> ");
string input = Console.ReadLine();
if (input.ToLower() == "exit")
break;
shell.WriteLine(input);
// 读取响应
string response = shell.Read();
Console.WriteLine(response);
}
shell.Close();
}
catch (Exception ex)
{
Console.WriteLine("Shell会话失败: " + ex.Message);
}
}
}
// 断开连接
public void Disconnect()
{
if (sshClient != null && sshClient.IsConnected)
{
sshClient.Disconnect();
}
}
// 端口转发
public void SetupPortForwarding(uint localPort, string remoteHost, uint remotePort)
{
if (sshClient != null && sshClient.IsConnected)
{
var forwarded = new ForwardedPortLocal("127.0.0.1", localPort, remoteHost, remotePort);
sshClient.AddForwardedPort(forwarded);
forwarded.Start();
Console.WriteLine(string.Format("端口转发已建立: localhost:{0} -> {1}:{2}",
localPort, remoteHost, remotePort));
}
}
}
三、Socket编程
1. 原始Socket编程
TCP Socket服务器
csharp
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class TcpSocketServer
{
private Socket serverSocket;
private int port;
private bool isRunning;
public TcpSocketServer(int port)
{
this.port = port;
}
public void Start()
{
try
{
// 创建Socket
serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
// 绑定端口
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, port);
serverSocket.Bind(endPoint);
// 开始监听
serverSocket.Listen(10);
isRunning = true;
Console.WriteLine("服务器启动,监听端口: " + port);
// 接受客户端连接
Thread acceptThread = new Thread(AcceptClients);
acceptThread.Start();
}
catch (Exception ex)
{
Console.WriteLine("服务器启动失败: " + ex.Message);
}
}
private void AcceptClients()
{
while (isRunning)
{
try
{
Socket clientSocket = serverSocket.Accept();
Console.WriteLine("客户端连接: " + clientSocket.RemoteEndPoint.ToString());
// 为每个客户端创建新线程
Thread clientThread = new Thread(HandleClient);
clientThread.Start(clientSocket);
}
catch (Exception ex)
{
Console.WriteLine("接受客户端失败: " + ex.Message);
}
}
}
private void HandleClient(object clientObj)
{
Socket clientSocket = (Socket)clientObj;
try
{
byte[] buffer = new byte[1024];
while (clientSocket.Connected)
{
int received = clientSocket.Receive(buffer);
if (received == 0)
break;
string message = Encoding.UTF8.GetString(buffer, 0, received);
Console.WriteLine("收到消息: " + message);
// 回显消息
string response = "服务器收到: " + message;
byte[] responseData = Encoding.UTF8.GetBytes(response);
clientSocket.Send(responseData);
}
}
catch (Exception ex)
{
Console.WriteLine("处理客户端失败: " + ex.Message);
}
finally
{
clientSocket.Close();
}
}
public void Stop()
{
isRunning = false;
if (serverSocket != null)
{
serverSocket.Close();
}
}
}
TCP Socket客户端
csharp
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class TcpSocketClient
{
private Socket clientSocket;
private string serverAddress;
private int port;
public TcpSocketClient(string server, int port)
{
this.serverAddress = server;
this.port = port;
}
public bool Connect()
{
try
{
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse(serverAddress), port);
clientSocket.Connect(serverEP);
Console.WriteLine("连接到服务器: " + serverEP.ToString());
return true;
}
catch (Exception ex)
{
Console.WriteLine("连接失败: " + ex.Message);
return false;
}
}
public void Send(string message)
{
if (clientSocket != null && clientSocket.Connected)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);
}
}
public string Receive()
{
if (clientSocket != null && clientSocket.Connected)
{
byte[] buffer = new byte[1024];
int received = clientSocket.Receive(buffer);
return Encoding.UTF8.GetString(buffer, 0, received);
}
return string.Empty;
}
// 异步发送
public void SendAsync(string message)
{
if (clientSocket != null && clientSocket.Connected)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.BeginSend(data, 0, data.Length, SocketFlags.None,
new AsyncCallback(SendCallback), clientSocket);
}
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
int bytesSent = socket.EndSend(ar);
Console.WriteLine("异步发送了 " + bytesSent + " 字节");
}
catch (Exception ex)
{
Console.WriteLine("异步发送失败: " + ex.Message);
}
}
// 异步接收
public void ReceiveAsync()
{
if (clientSocket != null && clientSocket.Connected)
{
StateObject state = new StateObject();
state.workSocket = clientSocket;
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.workSocket;
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
string message = Encoding.UTF8.GetString(state.buffer, 0, bytesRead);
Console.WriteLine("异步接收: " + message);
// 继续接收
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize,
SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
}
catch (Exception ex)
{
Console.WriteLine("异步接收失败: " + ex.Message);
}
}
public void Disconnect()
{
if (clientSocket != null && clientSocket.Connected)
{
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
// 状态对象
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
}
}
2. TcpClient类
TcpClient服务器(使用TcpListener)
csharp
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class TcpServer
{
private TcpListener listener;
private int port;
private bool isRunning;
public TcpServer(int port)
{
this.port = port;
}
public void Start()
{
try
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
isRunning = true;
Console.WriteLine("TCP服务器启动,端口: " + port);
Thread listenThread = new Thread(ListenForClients);
listenThread.Start();
}
catch (Exception ex)
{
Console.WriteLine("服务器启动失败: " + ex.Message);
}
}
private void ListenForClients()
{
while (isRunning)
{
try
{
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("客户端连接: " + client.Client.RemoteEndPoint.ToString());
Thread clientThread = new Thread(HandleClientComm);
clientThread.Start(client);
}
catch (Exception ex)
{
Console.WriteLine("接受客户端失败: " + ex.Message);
}
}
}
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
break;
}
if (bytesRead == 0)
{
break;
}
string receivedMessage = Encoding.UTF8.GetString(message, 0, bytesRead);
Console.WriteLine("收到: " + receivedMessage);
// 发送响应
string response = "服务器响应: " + receivedMessage;
byte[] responseData = Encoding.UTF8.GetBytes(response);
clientStream.Write(responseData, 0, responseData.Length);
clientStream.Flush();
}
tcpClient.Close();
}
public void Stop()
{
isRunning = false;
if (listener != null)
{
listener.Stop();
}
}
}
TcpClient客户端
csharp
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
public class TcpClientHelper
{
private TcpClient client;
private NetworkStream stream;
private string serverAddress;
private int port;
public TcpClientHelper(string server, int port)
{
this.serverAddress = server;
this.port = port;
}
public bool Connect()
{
try
{
client = new TcpClient();
client.Connect(serverAddress, port);
stream = client.GetStream();
Console.WriteLine("连接成功");
return true;
}
catch (Exception ex)
{
Console.WriteLine("连接失败: " + ex.Message);
return false;
}
}
public void Send(string message)
{
if (stream != null && stream.CanWrite)
{
byte[] data = Encoding.UTF8.GetBytes(message);
stream.Write(data, 0, data.Length);
stream.Flush();
}
}
public string Receive()
{
if (stream != null && stream.CanRead)
{
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer, 0, bytesRead);
}
return string.Empty;
}
// 使用StreamReader和StreamWriter
public void SendWithWriter(string message)
{
if (stream != null)
{
StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
writer.WriteLine(message);
writer.Flush();
}
}
public string ReceiveWithReader()
{
if (stream != null)
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
return reader.ReadLine();
}
return string.Empty;
}
// 异步操作
public void SendAsync(string message)
{
if (stream != null && stream.CanWrite)
{
byte[] data = Encoding.UTF8.GetBytes(message);
stream.BeginWrite(data, 0, data.Length,
new AsyncCallback(WriteCallback), stream);
}
}
private void WriteCallback(IAsyncResult ar)
{
try
{
NetworkStream stream = (NetworkStream)ar.AsyncState;
stream.EndWrite(ar);
Console.WriteLine("异步发送完成");
}
catch (Exception ex)
{
Console.WriteLine("异步发送失败: " + ex.Message);
}
}
public void Disconnect()
{
if (stream != null)
{
stream.Close();
}
if (client != null)
{
client.Close();
}
}
}
3. UDP编程
UDP服务器
csharp
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class UdpServer
{
private UdpClient udpServer;
private int port;
private bool isRunning;
private Thread receiveThread;
public UdpServer(int port)
{
this.port = port;
}
public void Start()
{
try
{
udpServer = new UdpClient(port);
isRunning = true;
Console.WriteLine("UDP服务器启动,端口: " + port);
receiveThread = new Thread(ReceiveData);
receiveThread.Start();
}
catch (Exception ex)
{
Console.WriteLine("UDP服务器启动失败: " + ex.Message);
}
}
private void ReceiveData()
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
while (isRunning)
{
try
{
byte[] data = udpServer.Receive(ref remoteEP);
string message = Encoding.UTF8.GetString(data);
Console.WriteLine("收到来自 " + remoteEP.ToString() + " 的消息: " + message);
// 发送响应
string response = "UDP服务器收到: " + message;
byte[] responseData = Encoding.UTF8.GetBytes(response);
udpServer.Send(responseData, responseData.Length, remoteEP);
}
catch (Exception ex)
{
if (isRunning)
{
Console.WriteLine("接收数据失败: " + ex.Message);
}
}
}
}
// 广播消息
public void Broadcast(string message)
{
if (udpServer != null)
{
byte[] data = Encoding.UTF8.GetBytes(message);
IPEndPoint broadcastEP = new IPEndPoint(IPAddress.Broadcast, port);
udpServer.Send(data, data.Length, broadcastEP);
}
}
// 组播支持
public void JoinMulticastGroup(string multicastIP)
{
try
{
IPAddress multicastAddress = IPAddress.Parse(multicastIP);
udpServer.JoinMulticastGroup(multicastAddress);
Console.WriteLine("加入组播组: " + multicastIP);
}
catch (Exception ex)
{
Console.WriteLine("加入组播组失败: " + ex.Message);
}
}
public void Stop()
{
isRunning = false;
if (udpServer != null)
{
udpServer.Close();
}
if (receiveThread != null)
{
receiveThread.Join(1000);
}
}
}
UDP客户端
csharp
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class UdpClientHelper
{
private UdpClient udpClient;
private string serverAddress;
private int port;
private Thread receiveThread;
private bool isListening;
public UdpClientHelper(string server, int port)
{
this.serverAddress = server;
this.port = port;
this.udpClient = new UdpClient();
}
public void Send(string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse(serverAddress), port);
udpClient.Send(data, data.Length, serverEP);
Console.WriteLine("发送消息: " + message);
}
catch (Exception ex)
{
Console.WriteLine("发送失败: " + ex.Message);
}
}
public void StartListening()
{
isListening = true;
receiveThread = new Thread(ReceiveData);
receiveThread.Start();
}
private void ReceiveData()
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
while (isListening)
{
try
{
byte[] data = udpClient.Receive(ref remoteEP);
string message = Encoding.UTF8.GetString(data);
Console.WriteLine("收到消息: " + message);
// 触发事件或处理消息
OnMessageReceived(message, remoteEP);
}
catch (Exception ex)
{
if (isListening)
{
Console.WriteLine("接收失败: " + ex.Message);
}
}
}
}
// 异步发送
public void SendAsync(string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse(serverAddress), port);
udpClient.BeginSend(data, data.Length, serverEP,
new AsyncCallback(SendCallback), udpClient);
}
catch (Exception ex)
{
Console.WriteLine("异步发送失败: " + ex.Message);
}
}
private void SendCallback(IAsyncResult ar)
{
try
{
UdpClient client = (UdpClient)ar.AsyncState;
int bytesSent = client.EndSend(ar);
Console.WriteLine("异步发送了 " + bytesSent + " 字节");
}
catch (Exception ex)
{
Console.WriteLine("发送回调失败: " + ex.Message);
}
}
// 异步接收
public void ReceiveAsync()
{
udpClient.BeginReceive(new AsyncCallback(ReceiveCallback), udpClient);
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
UdpClient client = (UdpClient)ar.AsyncState;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.EndReceive(ar, ref remoteEP);
string message = Encoding.UTF8.GetString(data);
Console.WriteLine("异步收到: " + message);
// 继续接收
client.BeginReceive(new AsyncCallback(ReceiveCallback), client);
}
catch (Exception ex)
{
Console.WriteLine("接收回调失败: " + ex.Message);
}
}
protected virtual void OnMessageReceived(string message, IPEndPoint sender)
{
// 可以在这里触发事件或处理消息
}
public void StopListening()
{
isListening = false;
if (receiveThread != null)
{
receiveThread.Join(1000);
}
}
public void Close()
{
StopListening();
if (udpClient != null)
{
udpClient.Close();
}
}
}
四、高级特性和最佳实践
1. 连接池管理
csharp
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
public class TcpConnectionPool
{
private Queue<TcpClient> availableConnections;
private List<TcpClient> allConnections;
private string serverAddress;
private int port;
private int maxPoolSize;
private int minPoolSize;
private object lockObject = new object();
public TcpConnectionPool(string server, int port, int minSize, int maxSize)
{
this.serverAddress = server;
this.port = port;
this.minPoolSize = minSize;
this.maxPoolSize = maxSize;
availableConnections = new Queue<TcpClient>();
allConnections = new List<TcpClient>();
InitializePool();
}
private void InitializePool()
{
lock (lockObject)
{
for (int i = 0; i < minPoolSize; i++)
{
TcpClient client = CreateConnection();
if (client != null)
{
availableConnections.Enqueue(client);
allConnections.Add(client);
}
}
}
}
private TcpClient CreateConnection()
{
try
{
TcpClient client = new TcpClient();
client.Connect(serverAddress, port);
return client;
}
catch (Exception ex)
{
Console.WriteLine("创建连接失败: " + ex.Message);
return null;
}
}
public TcpClient GetConnection()
{
lock (lockObject)
{
if (availableConnections.Count > 0)
{
TcpClient client = availableConnections.Dequeue();
// 检查连接是否有效
if (client.Connected)
{
return client;
}
else
{
allConnections.Remove(client);
return GetConnection(); // 递归获取新连接
}
}
else if (allConnections.Count < maxPoolSize)
{
// 创建新连接
TcpClient newClient = CreateConnection();
if (newClient != null)
{
allConnections.Add(newClient);
return newClient;
}
}
}
// 等待可用连接
Thread.Sleep(100);
return GetConnection();
}
public void ReturnConnection(TcpClient client)
{
lock (lockObject)
{
if (client != null && client.Connected)
{
availableConnections.Enqueue(client);
}
else
{
allConnections.Remove(client);
}
}
}
public void CloseAllConnections()
{
lock (lockObject)
{
foreach (TcpClient client in allConnections)
{
try
{
client.Close();
}
catch { }
}
availableConnections.Clear();
allConnections.Clear();
}
}
}
2. 心跳检测机制
csharp
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class HeartbeatClient
{
private TcpClient client;
private NetworkStream stream;
private Timer heartbeatTimer;
private DateTime lastHeartbeat;
private int heartbeatInterval = 30000; // 30秒
private int heartbeatTimeout = 60000; // 60秒超时
public bool IsConnected
{
get
{
return client != null && client.Connected;
}
}
public void Connect(string server, int port)
{
client = new TcpClient();
client.Connect(server, port);
stream = client.GetStream();
// 启动心跳
heartbeatTimer = new Timer(SendHeartbeat, null, 0, heartbeatInterval);
lastHeartbeat = DateTime.Now;
// 启动接收线程
Thread receiveThread = new Thread(ReceiveData);
receiveThread.Start();
}
private void SendHeartbeat(object state)
{
try
{
if (IsConnected)
{
// 检查超时
TimeSpan timeSinceLastHeartbeat = DateTime.Now - lastHeartbeat;
if (timeSinceLastHeartbeat.TotalMilliseconds > heartbeatTimeout)
{
Console.WriteLine("心跳超时,重新连接");
Reconnect();
return;
}
// 发送心跳包
byte[] heartbeatData = Encoding.UTF8.GetBytes("HEARTBEAT");
stream.Write(heartbeatData, 0, heartbeatData.Length);
stream.Flush();
}
}
catch (Exception ex)
{
Console.WriteLine("心跳发送失败: " + ex.Message);
Reconnect();
}
}
private void ReceiveData()
{
byte[] buffer = new byte[1024];
while (IsConnected)
{
try
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
if (message == "HEARTBEAT_ACK")
{
lastHeartbeat = DateTime.Now;
}
else
{
// 处理其他消息
ProcessMessage(message);
}
}
}
catch (Exception ex)
{
Console.WriteLine("接收数据失败: " + ex.Message);
break;
}
}
}
private void ProcessMessage(string message)
{
Console.WriteLine("收到消息: " + message);
}
private void Reconnect()
{
// 实现重连逻辑
Console.WriteLine("尝试重新连接...");
}
public void Disconnect()
{
if (heartbeatTimer != null)
{
heartbeatTimer.Dispose();
}
if (stream != null)
{
stream.Close();
}
if (client != null)
{
client.Close();
}
}
}
3. 数据传输协议封装
csharp
using System;
using System.IO;
using System.Text;
// 自定义协议包
public class ProtocolPacket
{
public byte Header { get; set; } // 包头标识
public ushort Length { get; set; } // 数据长度
public byte Command { get; set; } // 命令类型
public byte[] Data { get; set; } // 数据内容
public byte Checksum { get; set; } // 校验和
public const byte HEADER = 0xAA; // 固定包头
// 命令类型定义
public class Commands
{
public const byte LOGIN = 0x01;
public const byte LOGOUT = 0x02;
public const byte MESSAGE = 0x03;
public const byte FILE_TRANSFER = 0x04;
public const byte HEARTBEAT = 0x05;
}
// 将包序列化为字节数组
public byte[] ToBytes()
{
using (MemoryStream ms = new MemoryStream())
{
ms.WriteByte(HEADER);
// 写入长度(大端序)
ms.WriteByte((byte)(Length >> 8));
ms.WriteByte((byte)(Length & 0xFF));
ms.WriteByte(Command);
if (Data != null && Data.Length > 0)
{
ms.Write(Data, 0, Data.Length);
}
// 计算校验和
byte[] buffer = ms.ToArray();
Checksum = CalculateChecksum(buffer);
ms.WriteByte(Checksum);
return ms.ToArray();
}
}
// 从字节数组解析包
public static ProtocolPacket FromBytes(byte[] buffer)
{
if (buffer == null || buffer.Length < 5)
return null;
ProtocolPacket packet = new ProtocolPacket();
using (MemoryStream ms = new MemoryStream(buffer))
{
packet.Header = (byte)ms.ReadByte();
if (packet.Header != HEADER)
return null;
// 读取长度
byte highByte = (byte)ms.ReadByte();
byte lowByte = (byte)ms.ReadByte();
packet.Length = (ushort)((highByte << 8) | lowByte);
packet.Command = (byte)ms.ReadByte();
// 读取数据
if (packet.Length > 0)
{
packet.Data = new byte[packet.Length];
ms.Read(packet.Data, 0, packet.Length);
}
packet.Checksum = (byte)ms.ReadByte();
// 验证校验和
byte calculatedChecksum = CalculateChecksum(buffer, buffer.Length - 1);
if (calculatedChecksum != packet.Checksum)
{
Console.WriteLine("校验和错误");
return null;
}
}
return packet;
}
// 计算校验和
private static byte CalculateChecksum(byte[] data, int length = -1)
{
if (length == -1)
length = data.Length;
byte checksum = 0;
for (int i = 0; i < length; i++)
{
checksum ^= data[i];
}
return checksum;
}
// 创建消息包
public static ProtocolPacket CreateMessage(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
return new ProtocolPacket
{
Command = Commands.MESSAGE,
Data = data,
Length = (ushort)data.Length
};
}
// 创建心跳包
public static ProtocolPacket CreateHeartbeat()
{
return new ProtocolPacket
{
Command = Commands.HEARTBEAT,
Data = new byte[0],
Length = 0
};
}
}
// 协议处理器
public class ProtocolHandler
{
private byte[] receiveBuffer = new byte[4096];
private int bufferOffset = 0;
public void ProcessReceivedData(byte[] data, int length)
{
// 将新数据添加到缓冲区
Array.Copy(data, 0, receiveBuffer, bufferOffset, length);
bufferOffset += length;
// 尝试解析包
while (bufferOffset >= 5) // 最小包长度
{
// 查找包头
int headerIndex = -1;
for (int i = 0; i < bufferOffset; i++)
{
if (receiveBuffer[i] == ProtocolPacket.HEADER)
{
headerIndex = i;
break;
}
}
if (headerIndex == -1)
{
// 没有找到包头,清空缓冲区
bufferOffset = 0;
return;
}
// 移动数据到缓冲区开始
if (headerIndex > 0)
{
Array.Copy(receiveBuffer, headerIndex, receiveBuffer, 0, bufferOffset - headerIndex);
bufferOffset -= headerIndex;
}
// 检查是否有完整的包
if (bufferOffset < 3)
return;
ushort packetLength = (ushort)((receiveBuffer[1] << 8) | receiveBuffer[2]);
int totalPacketSize = 5 + packetLength; // 头(1) + 长度(2) + 命令(1) + 数据 + 校验(1)
if (bufferOffset < totalPacketSize)
return; // 包不完整
// 提取完整的包
byte[] packetData = new byte[totalPacketSize];
Array.Copy(receiveBuffer, 0, packetData, 0, totalPacketSize);
// 解析包
ProtocolPacket packet = ProtocolPacket.FromBytes(packetData);
if (packet != null)
{
HandlePacket(packet);
}
// 移除已处理的数据
Array.Copy(receiveBuffer, totalPacketSize, receiveBuffer, 0, bufferOffset - totalPacketSize);
bufferOffset -= totalPacketSize;
}
}
private void HandlePacket(ProtocolPacket packet)
{
switch (packet.Command)
{
case ProtocolPacket.Commands.MESSAGE:
string message = Encoding.UTF8.GetString(packet.Data);
Console.WriteLine("收到消息: " + message);
break;
case ProtocolPacket.Commands.HEARTBEAT:
Console.WriteLine("收到心跳包");
break;
default:
Console.WriteLine("未知命令: " + packet.Command);
break;
}
}
}
五、注意事项和最佳实践
性能优化
- 使用异步操作:避免阻塞主线程,提高并发处理能力
- 连接池:复用连接,减少创建和销毁连接的开销
- 缓冲区管理:合理设置缓冲区大小,避免频繁的内存分配
- 批量处理:尽可能批量发送数据,减少网络往返次数
安全考虑
- 使用加密协议:优先使用SFTP、SSH等加密协议
- 身份验证:实现强身份验证机制
- 输入验证:对所有输入数据进行验证和清理
- 超时设置:设置合理的连接和操作超时时间
错误处理
- 异常捕获:全面的异常处理机制
- 重试机制:实现自动重连和重试逻辑
- 日志记录:记录关键操作和错误信息
- 资源清理:确保在finally块中释放资源
兼容性注意
- 本文档所有代码示例都基于.NET Framework 4.0
- 避免使用C# 6.0及以后的新特性(如字符串插值、null条件运算符等)
- 某些功能(如SFTP、SSH)需要第三方库支持
- 注意不同操作系统的网络配置差异