首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 點對點通訊與檔案傳輸實作:Socket 非同步架構、多執行緒與協定設計

     編輯:關於C語言

架構概覽

基於 TCP Socket 的點對點通訊系統,支援文字訊息、檔案傳輸、遠端指令執行。採用每連線一執行緒模型,協定採用命令+描述+動態資料三段式結構。

協定設計

客戶端發送端實作

通用執行緒啟動器


private void StartThread(ThreadStart target) {
    var t = new Thread(target) { IsBackground = true };
    t.Start();
}

進度回調(UI 更新)


public void OnSendProgress(int total, int sent) {
    if (pbMain.Maximum != total) pbMain.Maximum = total;
    pbMain.Value = sent;
}

發送文字


private void StartSendText(string host, int port, string text) {
    var sender = new SendText(host, port, text, OnSendProgress);
    StartThread(sender.Send);
}

public class SendText {
    string Host, Info; int Port; CommunClass.OnSend OnSend;
    public SendText(string h, int p, string i, CommunClass.OnSend cb) {
        Host = h; Port = p; Info = i; OnSend = cb;
    }
    public void Send() {
        Socket s = null;
        try {
            s = CommunClass.ConnectToServer(Host, Port);
            CommunClass.WriteCommandToSocket(s, "SENDTEXT");
            CommunClass.WriteCommandDescToSocket(s, "");
            CommunClass.WriteDynamicTextToSocket(s, Info, OnSend);
        } catch (Exception ex) { MessageBox.Show(ex.Message); }
        finally { s?.Close(); }
    }
}

發送檔案


private void StartSendFile(string host, int port, string file) {
    var sender = new SendFile(host, port, file, pbMain);
    pbMain.Value = 0;
    StartThread(sender.Send);
}

public class SendFile {
    string Host, FileToSend; int Port; ProgressBar Pbar;
    public SendFile(string h, int p, string f, ProgressBar pb) {
        Host = h; Port = p; FileToSend = f; Pbar = pb;
    }
    public void Send() {
        Socket s = null;
        try {
            s = CommunClass.ConnectToServer(Host, Port);
            CommunClass.WriteCommandToSocket(s, "SENDFILE");
            CommunClass.WriteCommandDescToSocket(s, "");
            CommunClass.WriteFileToSocket(s, FileToSend, new CommunClass.OnSend(OnSendProgress));
        } catch (Exception ex) { MessageBox.Show(ex.Message); }
        finally { s?.Close(); }
    }
    void OnSendProgress(int total, int sent) {
        if (Pbar.Maximum != total) Pbar.Maximum = total;
        Pbar.Value = sent;
    }
}

遠端執行指令


public class ExecuteFile {
    string Host, FileName, CmdParam; int Port;
    public ExecuteFile(string h, int p, string fn, string cp) {
        Host = h; Port = p; FileName = fn; CmdParam = cp;
    }
    public void Send() {
        Socket s = null;
        try {
            s = CommunClass.ConnectToServer(Host, Port);
            CommunClass.WriteCommandToSocket(s, "EXECUTEFILE");
            CommunClass.WriteCommandDescToSocket(s, FileName);
            CommunClass.WriteDynamicTextToSocket(s, CmdParam, null);
            MessageBox.Show(CommunClass.ReadDynamicTextFromSocket(s));
        } catch (Exception ex) { MessageBox.Show(ex.Message); }
        finally { s?.Close(); }
    }
}

伺服器端接收實作

監聽啟動


private TcpListener _listener;
private void BuildServer(string addr, int port) {
    IPAddress ip = Dns.GetHostEntry(addr).AddressList[0];
    _listener = new TcpListener(ip, port);
}

private void StartListen() {
    _listener.Start();
    while (true) {
        Socket client = _listener.AcceptSocket();
        if (client != null) {
            var handler = new DealWithSocket(client, tbLog);
            StartThread(handler.DealWith);
        }
    }
}

連線處理器


public class DealWithSocket {
    Socket _socket; TextBox _log;
    public DealWithSocket(Socket s, TextBox log) { _socket = s; _log = log; }

    public void DealWith() {
        string cmd = CommunClass.ReadCommandFromSocket(_socket);
        string desc = CommunClass.ReadCommandDescFromSocket(_socket);
        Log(cmd);

        switch (cmd) {
            case "SENDFILE":
                CommunClass.ReadDynamicFileFromSocket(_socket, @"e:\rrr.txt");
                break;
            case "EXECUTEFILE":
                string param = CommunClass.ReadDynamicTextFromSocket(_socket);
                string result = ExecuteFile(desc, param);
                CommunClass.WriteDynamicTextToSocket(_socket, result, null);
                break;
            default:
                string detail = CommunClass.ReadDynamicTextFromSocket(_socket);
                Log(detail);
                break;
        }
        try { _socket.Close(); } catch { Log("Close error"); }
    }

    string ExecuteFile(string file, string args) {
        var proc = new Process {
            StartInfo = new ProcessStartInfo(file, args)
        };
        try { proc.Start(); return "OK"; }
        catch (Exception ex) { return ex.Message; }
    }

    void Log(string msg) {
        string line = $"{DateTime.Now:HH:mm:ss} {msg}\r\n";
        _log.Invoke((Action)(() => { _log.Text += line; _log.Refresh(); }));
    }
}

CommunClass 關鍵方法(假設實作)


public static class CommunClass {
    public delegate void OnSend(int total, int sent);

    public static Socket ConnectToServer(string host, int port) {
        var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        sock.Connect(host, port);
        return sock;
    }

    // 寫入命令(固定長度或分隔符)
    public static void WriteCommandToSocket(Socket s, string cmd) { ... }
    public static string ReadCommandFromSocket(Socket s) { ... }

    public static void WriteCommandDescToSocket(Socket s, string desc) { ... }
    public static string ReadCommandDescFromSocket(Socket s) { ... }

    // 動態文字:長度前綴 + 內容
    public static void WriteDynamicTextToSocket(Socket s, string text, OnSend progress) { ... }
    public static string ReadDynamicTextFromSocket(Socket s) { ... }

    // 檔案傳輸:檔案大小 + 分塊傳輸 + 進度回調
    public static void WriteFileToSocket(Socket s, string file, OnSend progress) { ... }
    public static void ReadDynamicFileFromSocket(Socket s, string savePath) { ... }
}

關鍵技術點與改進方向

優點

  • 協定清晰,擴充新命令容易
  • 執行緒隔離,單一連線錯誤不影響其他
  • 進度回調提供良好 UX
  • 檔案/文字/指令統一框架

缺點與風險

階段內容範例
命令操作類型SENDTEXT, SENDFILE, EXECUTEFILE
描述參數/檔名檔案路徑、執行參數
動態資料實際承載文字內容、檔案二進位流
議題風險改進
每連線一執行緒高併發時執行緒耗盡改用 `SocketAsyncEventArgs` / `async-await` / IOCP
無加密傳輸資料竊聽、竄改加入 TLS (SslStream) 或應用層加密
無驗證授權任意連線可執行指令(後門風險)加入 Token/憑證驗證、命令白名單
檔案傳輸無斷點續傳大檔中斷需重傳支援 Range/Offset 斷點續傳
UI 跨執行緒直接存取可能例外統一用 `Control.Invoke` / `SynchronizationContext`
緩衝區大小固定 1024效能非最佳動態調整或使用 `NetworkStream`

現代化重構建議


// 非同步接受
_listener.Start();
while (true) {
    Socket client = await _listener.AcceptSocketAsync();
    _ = HandleClientAsync(client);  // Fire-and-forget
}

async Task HandleClientAsync(Socket client) {
    using var stream = new NetworkStream(client, true);
    using var reader = new BinaryReader(stream);
    using var writer = new BinaryWriter(stream);
    
    string cmd = reader.ReadString();
    // ... 協定解析
}

總結

此實作展示了 Socket 程式設計核心概念:連線建立、協定設計、資料序列化、多執行緒並發、進度報告。雖架構屬傳統阻塞模型,但邏輯清晰適合教學與中小規模應用。生產系統建議遷移至非同步 IO、加入安全性層、使用成熟框架(SignalR、gRPC、WebSocket)替代原始 Socket。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved