Socket详解

文章目录

Socket详解

1、基础概念

(1)概念
  • Socket位于应用层与传输层之间,作为应用程序与TCP/IP协议栈的桥梁。
  • 通过 IP地址 + 协议类型(TCP/UDP)+ 端口号 三元组唯一标识网络中的进程。
  • 在C#中通过 System.Net.Sockets 命名空间下的 Socket 类实现。
  • 计算机网络相关知识请参考:https://blog.csdn.net/liyou123456789/article/details/122731144
(2)通信协议支持
特性 TCP Socket UDP Socket
连接方式 面向连接(可靠传输) 无连接(不可靠)
数据保证 有序、不丢失 可能乱序、丢失
适用场景 文件传输、网页访问(HTTP) 视频流、实时游戏
复杂度 高(需维护连接状态) 低(轻量级)
(3)应用场景
  • 即时通讯工具(如微信、QQ):基于TCP保证消息可靠送达,通过长连接实现实时双向通信。
  • Web服务器(HTTP服务):HTTP协议底层依赖TCP Socket,服务器监听80端口处理请求。
  • 物联网设备控制:设备作为Socket客户端定时上报数据,服务器远程发送指令。
  • 实时数据推送:服务端主动向客户端推送消息(如股票行情),需WebSocket等基于Socket的扩展。

2、通信流程

(1)流程图
(2)服务端
csharp 复制代码
// 初始化Socket 
Socket serverSocket = new Socket(AddressFamily.InterNetwork, 
                                SocketType.Stream, 
                                ProtocolType.Tcp);
// 绑定端口并监听 
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 9000);
serverSocket.Bind(localEP);
serverSocket.Listen(10); // 允许10个连接排队 
 
// 异步接受连接 
serverSocket.BeginAccept(new AsyncCallback(OnClientConnected), null);
 
// 处理客户端连接
private void OnClientConnected(IAsyncResult ar) {
    Socket clientSocket = serverSocket.EndAccept(ar);
    // 启动新线程处理通信 
    Thread clientThread = new Thread(HandleClient);
    clientThread.Start(clientSocket);
}
(3)客户端
csharp 复制代码
Socket clientSocket = new Socket(AddressFamily.InterNetwork, 
                                SocketType.Stream, 
                                ProtocolType.Tcp);
// 连接服务器 
clientSocket.Connect("127.0.0.1", 9000); 
 
// 异步接收数据
byte[] buffer = new byte[1024];
clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, 
                         new AsyncCallback(OnDataReceived), buffer);
(4)关键技术
  • 异步通信模型
    • 原理:使用 BeginAccept/BeginReceive 避免阻塞主线程,通过回调函数处理事件。
    • 优势:支持高并发,适用于服务端处理多客户端请求。
  • 数据边界处理
    • TCP粘包问题:需自定义协议(如消息头声明长度)。
    • UDP数据报:天然有边界,但需处理丢包和乱序。
  • 跨线程UI更新 :WinForm中必须通过 Control.Invoke 避免线程冲突:
csharp 复制代码
this.Invoke((MethodInvoker)delegate {
    txtChatBox.Text += "收到消息: " + message;
});
(5)注意事项
  • 防止资源泄漏:必须显式关闭Socket
csharp 复制代码
socket.Shutdown(SocketShutdown.Both); 
socket.Close();
  • 端口占用问题:服务端关闭后需等待2MSL(约1-4分钟)才能复用端口,可通过设置选项解决:
csharp 复制代码
socket.SetSocketOption(SocketOptionLevel.Socket, 
                      SocketOptionName.ReuseAddress, true);
  • 数据编码与解析:网络字节序需统一(大端序),文本数据建议用JSON/Protobuf格式化。
  • 调试工具推荐
    • Wireshark:抓包分析协议细节。
    • 日志记录:关键操作(连接/断开/异常)写入日志文件。
  • 性能优化
    • 使用缓冲区池(Buffer Pool)减少内存分配开销。
    • 异步IO配合 SocketAsyncEventArgs 替代APM模型(更高性能)。

3、聊天室功能

(1)项目概述
  • net 版本:net8
(2)服务端(控制台)
csharp 复制代码
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Server
{
    internal class Program
    {
        static List<Socket> clientSockets = new List<Socket>();
        static readonly object lockObj = new object();

        static void Main()
        {
            const int PORT = 3000;
            Socket serverSocket = new Socket(AddressFamily.InterNetwork,
                                            SocketType.Stream,
                                            ProtocolType.Tcp);

            // 绑定端口并监听 
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, PORT);
            serverSocket.Bind(localEP);
            serverSocket.Listen(10);
            Console.WriteLine($"服务器启动,监听端口 {PORT}...");

            // 异步接受客户端连接
            while (true)
            {
                Socket clientSocket = serverSocket.Accept();
                lock (lockObj) clientSockets.Add(clientSocket);
                Console.WriteLine($"客户端接入: {clientSocket.RemoteEndPoint}");

                // 为每个客户端创建独立线程
                Thread clientThread = new Thread(() => HandleClient(clientSocket));
                clientThread.Start();
            }
        }

        static void HandleClient(Socket clientSocket)
        {
            byte[] buffer = new byte[1024];
            try
            {
                while (true)
                {
                    int bytesRead = clientSocket.Receive(buffer);
                    if (bytesRead == 0) break;  // 客户端断开连接

                    string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    Console.WriteLine($"收到消息: {message}");

                    // 广播消息给所有客户端
                    BroadcastMessage(message, clientSocket);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"错误: {ex.Message}");
            }
            finally
            {
                lock (lockObj) clientSockets.Remove(clientSocket);
                clientSocket.Close();
                Console.WriteLine($"客户端断开: {clientSocket.RemoteEndPoint}");
            }
        }

        static void BroadcastMessage(string message, Socket senderSocket)
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            lock (lockObj)
            {
                foreach (Socket client in clientSockets)
                {
                    if (client != senderSocket && client.Connected)
                    {
                        try
                        {
                            client.Send(data);
                        }
                        catch { /* 忽略发送失败的客户端 */ }
                    }
                }
            }
        }
    }
}
(3)客户端(控制台)
csharp 复制代码
using System.Net.Sockets;
using System.Text;

namespace Client
{
    internal class Program
    {
        static Socket clientSocket;

        static void Main()
        {
            const string SERVER_IP = "127.0.0.1";
            const int PORT = 3000;

            clientSocket = new Socket(AddressFamily.InterNetwork,
                                     SocketType.Stream,
                                     ProtocolType.Tcp);

            try
            {
                clientSocket.Connect(SERVER_IP, PORT);
                Console.WriteLine("已连接到服务器,输入消息开始聊天 (输入exit退出)");

                // 启动接收线程 
                Thread receiveThread = new Thread(ReceiveMessages);
                receiveThread.IsBackground = true;
                receiveThread.Start();

                // 主线程处理输入发送 
                while (true)
                {
                    string input = Console.ReadLine();
                    if (input.ToLower() == "exit") break;

                    byte[] data = Encoding.UTF8.GetBytes(input);
                    clientSocket.Send(data);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"连接错误: {ex.Message}");
            }
            finally
            {
                clientSocket?.Close();
            }
        }

        static void ReceiveMessages()
        {
            byte[] buffer = new byte[1024];
            try
            {
                while (true)
                {
                    int bytesRead = clientSocket.Receive(buffer);
                    if (bytesRead == 0) break;

                    string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    Console.WriteLine($"收到: {message}");
                }
            }
            catch
            {
                Console.WriteLine("与服务器断开连接");
            }
        }
    }
}
(4)核心功能说明
  • 服务端机制
    • 使用Accept()阻塞监听客户端连接
    • 为每个客户端创建独立线程处理通信
    • 通过客户端列表clientSockets实现消息广播
    • 线程锁lockObj保证多线程安全
  • 客户端机制
    • 主线程处理用户输入和发送
    • 后台线程持续接收服务器消息
    • 使用Encoding.UTF8解决中文乱码问题
  • 广播策略
    • 遍历所有客户端Socket发送消息
    • 跳过消息发送者自身(senderSocket)
    • 异常处理避免断开客户端导致崩溃
(5)使用步骤
  • 启动服务端程序(监听3000端口)
  • 启动多个客户端程序(连接127.0.0.1:3000)
  • 在任意客户端输入消息,其他客户端将实时接收

4、大文件传输

(1)项目概述
  • 本Socket文件传输程序实现了高效、可靠的文件传输功能,包含三个核心特性:基于SHA256的分片校验机制、断点续传功能以及传输速度优化。
(2)接收端(控制台)
csharp 复制代码
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;

namespace FileReceiver
{
    internal class Program
    {
        private const int BufferSize = 64 * 1024; // 64KB 分片大小
        private const int Port = 4000;
        private static readonly string SavePath = @"D:\ReceivedFiles\";

        static void Main()
        {
            Directory.CreateDirectory(SavePath);

            // 创建监听Socket
            TcpListener listener = new TcpListener(IPAddress.Any, Port);
            listener.Start();
            Console.WriteLine($"文件接收服务已启动,监听端口: {Port}");

            while (true)
            {
                // 接受客户端连接 
                using (TcpClient client = listener.AcceptTcpClient())
                using (NetworkStream stream = client.GetStream())
                {
                    Console.WriteLine($"客户端已连接: {client.Client.RemoteEndPoint}");

                    // 传输速度优化
                    client.NoDelay = true; // 禁用Nagle算法
                    client.ReceiveBufferSize = 64 * 1024; // 64KB缓冲区

                    // 接收文件头信息(文件名+文件大小)
                    byte[] headerBuffer = new byte[512];
                    int headerSize = stream.Read(headerBuffer, 0, headerBuffer.Length);
                    string header = Encoding.UTF8.GetString(headerBuffer, 0, headerSize);

                    // 解析文件元数据
                    string[] headerParts = header.Split('|');
                    if (headerParts.Length < 3)
                    {
                        Console.WriteLine("无效文件头格式");
                        continue;
                    }

                    string fileName = headerParts[1];
                    long fileSize = long.Parse(headerParts[2]);
                    string filePath = Path.Combine(SavePath, fileName);

                    // 处理断点续传请求
                    bool isResume = false;
                    long resumePosition = 0;

                    if (headerParts[0] == "RESUME")
                    {
                        isResume = true;
                        resumePosition = long.Parse(headerParts[3]);
                        Console.WriteLine($"收到断点续传请求: {fileName},从 {resumePosition} 字节处继续接收");

                        // 检查文件是否存在且大小正确
                        if (File.Exists(filePath))
                        {
                            FileInfo fileInfo = new FileInfo(filePath);
                            if (fileInfo.Length == resumePosition)
                            {
                                // 发送确认消息
                                byte[] confirmBytes = Encoding.UTF8.GetBytes("OK");
                                stream.Write(confirmBytes, 0, confirmBytes.Length);
                                Console.WriteLine($"开始接收: {fileName} ({fileSize}字节),继续从 {resumePosition} 字节处接收");
                            }
                            else
                            {
                                // 文件大小不匹配,重新开始传输
                                byte[] rejectBytes = Encoding.UTF8.GetBytes("REJECT");
                                stream.Write(rejectBytes, 0, rejectBytes.Length);
                                Console.WriteLine("文件大小不匹配,将重新开始传输");
                                isResume = false;
                            }
                        }
                        else
                        {
                            // 文件不存在,重新开始传输
                            byte[] rejectBytes = Encoding.UTF8.GetBytes("REJECT");
                            stream.Write(rejectBytes, 0, rejectBytes.Length);
                            Console.WriteLine("文件不存在,将重新开始传输");
                            isResume = false;
                        }
                    }
                    else if (headerParts[0] == "FILE")
                    {
                        Console.WriteLine($"开始接收: {fileName} ({fileSize}字节)");
                    }
                    else
                    {
                        Console.WriteLine("无效的文件头类型");
                        continue;
                    }

                    // 分片接收文件内容
                    FileMode fileMode = isResume ? FileMode.Append : FileMode.Create;
                    using (FileStream fs = new FileStream(filePath, fileMode))
                    using (SHA256 sha256 = SHA256.Create())
                    {
                        byte[] buffer = new byte[BufferSize];
                        long totalReceived = isResume ? resumePosition : 0;

                        // 如果是断点续传,记录当前文件大小作为起始接收位置
                        if (isResume)
                        {
                            fs.Seek(0, SeekOrigin.End);
                        }

                        while (totalReceived < fileSize)
                        {
                            // 读取校验和长度
                            byte[] checksumLengthBytes = new byte[sizeof(int)];
                            int checksumLengthRead = stream.Read(checksumLengthBytes, 0, sizeof(int));
                            if (checksumLengthRead != sizeof(int))
                            {
                                Console.WriteLine("接收校验和长度失败");
                                break;
                            }
                            int checksumLength = BitConverter.ToInt32(checksumLengthBytes, 0);

                            // 读取校验和
                            byte[] receivedChecksum = new byte[checksumLength];
                            int checksumRead = stream.Read(receivedChecksum, 0, checksumLength);
                            if (checksumRead != checksumLength)
                            {
                                Console.WriteLine("接收校验和失败");
                                break;
                            }

                            // 读取数据长度
                            byte[] dataLengthBytes = new byte[sizeof(int)];
                            int dataLengthRead = stream.Read(dataLengthBytes, 0, sizeof(int));
                            if (dataLengthRead != sizeof(int))
                            {
                                Console.WriteLine("接收数据长度失败");
                                break;
                            }
                            int dataLength = BitConverter.ToInt32(dataLengthBytes, 0);

                            // 读取实际数据
                            int bytesRead = stream.Read(buffer, 0, dataLength);
                            if (bytesRead != dataLength)
                            {
                                Console.WriteLine("接收数据失败");
                                break;
                            }

                            // 验证校验和
                            byte[] computedChecksum = sha256.ComputeHash(buffer, 0, bytesRead);
                            bool checksumMatch = receivedChecksum.SequenceEqual(computedChecksum);
                            if (!checksumMatch)
                            {
                                Console.WriteLine("校验和不匹配,传输错误");
                                break;
                            }

                            // 写入文件
                            fs.Write(buffer, 0, bytesRead);
                            totalReceived += bytesRead;

                            // 显示进度 
                            Console.Write($"\r进度: {totalReceived * 100 / fileSize}%");
                        }
                        fs.Flush();
                    }
                    Console.WriteLine($"\n文件接收完成: {filePath}");
                }
            }
        }
    }
}
(3)发送端(控制台)
csharp 复制代码
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;

namespace FileSender
{
    internal class Program
    {
        private const int BufferSize = 64 * 1024; // 64KB 分片大小
        private const int Port = 4000;
        private const string ServerIP = "127.0.0.1";

        static void Main()
        {
            string filePath = "test_file.txt";

            if (!File.Exists(filePath))
            {
                Console.WriteLine("文件不存在");
                return;
            }
            Console.WriteLine($"使用测试文件: {filePath}");

            FileInfo fileInfo = new FileInfo(filePath);
            string fileName = fileInfo.Name;
            long fileSize = fileInfo.Length;

            // 计算分片数量
            int totalChunks = (int)Math.Ceiling((double)fileSize / BufferSize);

            try
            {
                using (TcpClient client = new TcpClient(ServerIP, Port))
                using (NetworkStream stream = client.GetStream())
                {
                    // 传输速度优化
                    client.NoDelay = true; // 禁用Nagle算法
                    client.SendBufferSize = 64 * 1024; // 64KB缓冲区

                    // 检查是否需要断点续传
                    string tempFilePath = Path.Combine(Path.GetTempPath(), $"{fileName}.temp");
                    long startPosition = 0;

                    if (File.Exists(tempFilePath))
                    {
                        // 读取上次传输的位置
                        using (BinaryReader reader = new BinaryReader(File.OpenRead(tempFilePath)))
                        {
                            startPosition = reader.ReadInt64();
                        }

                        if (startPosition < fileSize)
                        {
                            Console.WriteLine($"检测到未完成的传输,将从 {startPosition} 字节处继续传输");
                            // 发送断点续传请求
                            string resumeHeader = $"RESUME|{fileName}|{fileSize}|{startPosition}";
                            byte[] resumeHeaderBytes = Encoding.UTF8.GetBytes(resumeHeader);
                            stream.Write(resumeHeaderBytes, 0, resumeHeaderBytes.Length);

                            // 等待服务器确认
                            byte[] confirmBuffer = new byte[10];
                            stream.Read(confirmBuffer, 0, confirmBuffer.Length);
                            string confirm = Encoding.UTF8.GetString(confirmBuffer).Trim();
                            if (confirm != "OK")
                            {
                                Console.WriteLine("服务器不支持断点续传,将重新开始传输");
                                startPosition = 0;
                            }
                        }
                        else
                        {
                            Console.WriteLine("文件已传输完成,无需再次传输");
                            return;
                        }
                    }

                    // 如果不是断点续传,则发送完整的文件头
                    if (startPosition == 0)
                    {
                        string header = $"FILE|{fileName}|{fileSize}";
                        byte[] headerBytes = Encoding.UTF8.GetBytes(header);
                        stream.Write(headerBytes, 0, headerBytes.Length);
                    }

                    Console.WriteLine($"开始发送: {fileName} ({fileSize}字节)");

                    // 分片发送文件内容
                    using (FileStream fs = File.OpenRead(filePath))
                    using (SHA256 sha256 = SHA256.Create())
                    {
                        // 如果是断点续传,跳转到上次传输的位置
                        if (startPosition > 0)
                        {
                            fs.Seek(startPosition, SeekOrigin.Begin);
                        }

                        byte[] buffer = new byte[BufferSize];
                        int bytesRead;
                        long totalSent = startPosition;

                        // 创建临时文件记录传输进度
                        using (BinaryWriter progressWriter = new BinaryWriter(File.Open(tempFilePath, FileMode.Create)))
                        {
                            while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                // 增加分片校验机制
                                byte[] checksum = sha256.ComputeHash(buffer, 0, bytesRead);
                                stream.Write(BitConverter.GetBytes(checksum.Length), 0, sizeof(int));
                                stream.Write(checksum, 0, checksum.Length);
                                stream.Write(BitConverter.GetBytes(bytesRead), 0, sizeof(int));
                                stream.Write(buffer, 0, bytesRead);

                                totalSent += bytesRead;

                                // 保存传输进度
                                progressWriter.Seek(0, SeekOrigin.Begin);
                                progressWriter.Write(totalSent);
                                progressWriter.Flush();

                                // 显示进度 
                                Console.Write($"\r进度: {totalSent * 100 / fileSize}%");
                            }
                            stream.Flush();
                        }

                        // 传输完成后删除临时文件
                        if (totalSent == fileSize && File.Exists(tempFilePath))
                        {
                            File.Delete(tempFilePath);
                        }
                    }
                    Console.WriteLine("\n文件发送完成");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"传输错误: {ex.Message}");
            }
        }
    }
}
(4)核心功能说明
  • 分片校验机制
    • 功能说明:使用SHA256加密算法对每个数据分片进行校验,确保文件传输的完整性和可靠性。
    • 发送端(FileSender)实现
      • 在发送每个数据分片前,使用SHA256算法计算该分片的校验和
      • 按照固定格式发送数据:先发送校验和长度,然后是校验和本身,接着是数据长度,最后是实际数据内容
      • 使用64KB作为分片大小,既保证了传输效率,也确保了校验准确性
    • 接收端(FileReceiver)实现
      • 按照发送端定义的格式接收数据:先接收校验和长度,然后接收校验和,接着接收数据长度,最后接收实际数据
      • 使用相同的SHA256算法计算接收到的数据分片的校验和
      • 将计算得到的校验和与接收到的校验和进行比对,确保数据完整性
      • 如果校验失败,可触发重传机制(当前版本未实现自动重传)
    • 代码实现关键点
csharp 复制代码
// 发送端计算和发送校验和
byte[] checksum = sha256.ComputeHash(buffer, 0, bytesRead);
stream.Write(BitConverter.GetBytes(checksum.Length), 0, sizeof(int));
stream.Write(checksum, 0, checksum.Length);
stream.Write(BitConverter.GetBytes(bytesRead), 0, sizeof(int));
stream.Write(buffer, 0, bytesRead);

// 接收端接收和验证校验和
// 读取校验和长度、校验和、数据长度和实际数据
// 计算接收到数据的校验和并与发送的校验和比对
  • 断点续传功能
    • 功能说明:在文件传输过程中如果发生中断(如网络故障、程序崩溃等),支持从中断位置继续传输,而无需重新开始。
    • 发送端(FileSender)实现
      • 使用临时文件记录每次传输的进度位置
      • 程序启动时检查是否存在未完成的传输任务
      • 如果存在未完成传输,发送特殊的RESUME头信息给接收端,包含文件名、总大小和期望的起始位置
      • 等待接收端确认是否可以继续传输
      • 如果接收端同意继续,从指定位置开始读取和发送文件内容
      • 传输完成后自动删除临时进度文件
    • 接收端(FileReceiver)实现
      • 解析接收到的文件头信息,区分普通传输请求(FILE)和断点续传请求(RESUME)
      • 对于断点续传请求,检查目标文件是否存在且大小与请求的起始位置匹配
      • 根据检查结果,向发送端发送确认(OK)或拒绝(REJECT)响应
      • 如果确认继续传输,使用FileMode.Append模式打开文件,并从文件末尾开始写入数据
    • 代码实现关键点
csharp 复制代码
// 发送端发送断点续传请求
string tempFilePath = Path.Combine(Path.GetTempPath(), $"{fileName}.temp");
if (File.Exists(tempFilePath))
{
    using (BinaryReader reader = new BinaryReader(File.OpenRead(tempFilePath)))
    {
        startPosition = reader.ReadInt64();
    }
    string resumeHeader = $"RESUME|{fileName}|{fileSize}|{startPosition}";
    // 发送断点续传请求并等待确认
}

// 接收端处理断点续传请求
if (headerParts[0] == "RESUME")
{
    resumePosition = long.Parse(headerParts[3]);
    // 检查文件状态并发送确认/拒绝响应
    FileMode fileMode = isResume ? FileMode.Append : FileMode.Create;
}
  • 传输速度优化
    • 功能说明:通过一系列配置优化,显著提高文件传输速度。
    • 增大缓冲区大小
      • 将原有的4KB缓冲区增大到64KB,减少网络交互次数
      • 在发送端和接收端统一使用相同的缓冲区大小,确保最佳匹配
    • 禁用Nagle算法
      • Nagle算法会延迟小数据包的发送以提高吞吐量,但会增加延迟
      • 在文件传输场景中,禁用Nagle算法可以减少延迟,提高实时性
    • 优化Socket缓冲区设置
      • 显式设置发送和接收缓冲区大小为64KB,确保与分片大小匹配
      • 减少操作系统层面的缓冲区管理开销
    • 代码实现关键点
csharp 复制代码
// 传输速度优化配置
client.NoDelay = true; // 禁用Nagle算法
client.SendBufferSize = 64 * 1024; // 64KB发送缓冲区
// 接收端类似设置client.ReceiveBufferSize
(5)技术架构与流程
  • 整体架构
    • 发送端(FileSender):负责读取本地文件,计算校验和,发送文件数据,并支持断点续传
    • 接收端(FileReceiver):负责监听连接,接收文件数据,验证校验和,保存文件,并支持断点续传
    • 通信协议:基于TCP协议实现可靠传输,自定义简单协议头格式
  • 传输流程
    • 连接建立阶段
      • 接收端启动并监听指定端口
      • 发送端连接到接收端
      • 双方配置Socket参数(禁用Nagle算法,设置缓冲区大小等)
    • 文件头传输阶段
      • 发送端确定使用普通传输(FILE头)还是断点续传(RESUME头)
      • 发送端发送文件头信息
      • 接收端解析文件头并做相应处理
      • 对于断点续传请求,接收端发送确认/拒绝响应
    • 文件内容传输阶段
      • 发送端以64KB为单位分片读取文件
      • 对每个分片计算SHA256校验和
      • 按顺序发送校验和长度、校验和、数据长度和数据内容
      • 接收端接收并验证每个分片
      • 发送端实时保存传输进度
    • 传输完成阶段
      • 发送端完成所有数据发送
      • 发送端删除临时进度文件
      • 双方关闭连接
(6)使用说明
  • 配置与依赖
    • 开发环境:.NET Framework/.NET Core
    • 依赖库:System.Net.Sockets、System.Security.Cryptography、System.IO
    • 端口配置:默认使用4000端口(可在代码中修改Port常量)
    • 保存路径:接收端默认保存到D:\ReceivedFiles\(可在代码中修改SavePath常量)
  • 运行方法
    • 首先启动接收端程序:
plain 复制代码
dotnet run --project FileReceiver\FileReceiver.csproj
复制代码
- 然后启动发送端程序:
    * 发送端会自动使用项目目录下的test_file.txt作为测试文件进行传输
plain 复制代码
dotnet run --project FileSender\FileSender.csproj
(7)扩展建议
  • 实现自动重传机制,在校验失败时自动请求重传
  • 添加用户认证机制,增强安全性
  • 支持多文件并发传输
  • 添加图形用户界面,提高易用性
  • 实现传输限速功能,避免占用过多网络带宽
相关推荐
葛小白18 小时前
C#数据类型:List
开发语言·c#
weixin_456904279 小时前
基于C#的文档处理
开发语言·c#
gc_229911 小时前
C#测试调用OpenXml合并word文档的表格单元格
c#·openxml·合并单元格
唐青枫12 小时前
C#.NET PeriodicTimer 深入解析:高效异步定时器的正确打开方式
c#·.net
赵庆明老师1 天前
C# 结合Redis Cache 访问MySQL数据库
数据库·redis·c#
yi碗汤园1 天前
【一文了解】八大排序-冒泡排序、选择排序
开发语言·前端·算法·unity·c#·1024程序员节
c#上位机1 天前
wpf之数据类型转换
c#·wpf·mvvm
宝桥南山1 天前
.NET - .NET Aspire的Command-Line和GitHub Copilot
microsoft·微软·c#·asp.net·.net·.netcore
向宇it1 天前
【推荐100个unity插件】unity易于使用模块化设计的天空、体积云和天气系统——Enviro 3
游戏·3d·unity·c#·游戏引擎