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

C# 網路程式設計:協議與檔案傳輸 (4) — 伺服器端非同步架構與檔案接收完整實作

     編輯:關於C語言

3.1 伺服器端實作

將問題拆為「發送資料」與「接收資料」兩部分。程式碼重點在思路而非語法,若從第一篇讀到此應易理解。

class Server {
    static void Main(string[] args) {
        Console.WriteLine("Server is running ... ");
        IPAddress ip = IPAddress.Parse("127.0.0.1");
        TcpListener listener = new TcpListener(ip, 8500);
        listener.Start(); // 監聽控制埠 8500
        Console.WriteLine("Start Listening ...");

        while (true) {
            TcpClient client = listener.AcceptTcpClient(); // 同步取得控制連線
            RemoteClient wrapper = new RemoteClient(client);
            wrapper.BeginRead(); // 啟動非同步讀取
        }
    }
}

public class RemoteClient {
    private TcpClient client;
    private NetworkStream streamToClient;
    private const int BufferSize = 8192;
    private byte[] buffer;
    private ProtocolHandler handler;

    public RemoteClient(TcpClient client) {
        this.client = client;
        Console.WriteLine("\nClient Connected!{0} <-- {1}",
            client.Client.LocalEndPoint, client.Client.RemoteEndPoint);
        streamToClient = client.GetStream();
        buffer = new byte[BufferSize];
        handler = new ProtocolHandler();
    }

    public void BeginRead() {
        AsyncCallback callback = new AsyncCallback(OnReadComplete);
        streamToClient.BeginRead(buffer, 0, BufferSize, callback, null);
    }

    private void OnReadComplete(IAsyncResult ar) {
        int bytesRead = 0;
        try {
            lock (streamToClient) {
                bytesRead = streamToClient.EndRead(ar);
                Console.WriteLine("\nReading data, {0} bytes ...", bytesRead);
            }
            if (bytesRead == 0) throw new Exception("讀取到 0 位元組");

            string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);
            Array.Clear(buffer, 0, buffer.Length); // 清除髒讀

            // 解析協議陣列(處理合併/拆分)
            string[] protocolArray = handler.GetProtocol(msg);
            foreach (string pro in protocolArray) {
                // 非同步分派處理,避免阻塞讀取迴圈
                ParameterizedThreadStart start = new ParameterizedThreadStart(handleProtocol);
                start.BeginInvoke(pro, null, null);
            }

            // 重新啟動讀取,形成無限迴圈
            lock (streamToClient) {
                AsyncCallback callback = new AsyncCallback(OnReadComplete);
                streamToClient.BeginRead(buffer, 0, BufferSize, callback, null);
            }
        } catch (Exception ex) {
            if (streamToClient != null) streamToClient.Dispose();
            client.Close();
            Console.WriteLine(ex.Message);
        }
    }

    private void handleProtocol(object obj) {
        string pro = obj as string;
        ProtocolHelper helper = new ProtocolHelper(pro);
        FileProtocol protocol = helper.GetProtocol();

        if (protocol.Mode == FileRequestMode.Send) {
            receiveFile(protocol); // 客戶端送檔 → 伺服器收檔
        } else if (protocol.Mode == FileRequestMode.Receive) {
            // sendFile(protocol); // 待實作
        }
    }

    private void receiveFile(FileProtocol protocol) {
        // 取得客戶端 IP,依協議指定埠號連回
        IPEndPoint endpoint = client.Client.RemoteEndPoint as IPEndPoint;
        IPAddress ip = endpoint.Address;
        endpoint = new IPEndPoint(ip, protocol.Port);

        TcpClient localClient;
        try {
            localClient = new TcpClient();
            localClient.Connect(endpoint);
        } catch {
            Console.WriteLine("無法連接到客戶端 --> {0}", endpoint); return;
        }

        NetworkStream streamToClient = localClient.GetStream();
        string path = Environment.CurrentDirectory + "/" + generateFileName(protocol.FileName);

        byte[] fileBuffer = new byte[1024];
        FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write);
        int bytesRead, totalBytes = 0;
        do {
            bytesRead = streamToClient.Read(fileBuffer, 0, fileBuffer.Length);
            fs.Write(fileBuffer, 0, bytesRead);
            totalBytes += bytesRead;
            Console.WriteLine("Receiving {0} bytes ...", totalBytes);
        } while (bytesRead > 0);

        Console.WriteLine("Total {0} bytes received, Done!", totalBytes);
        streamToClient.Dispose(); fs.Dispose(); localClient.Close();
    }

    private string generateFileName(string fileName) {
        DateTime now = DateTime.Now;
        return String.Format("{0}_{1}_{2}_{3}", now.Minute, now.Second, now.Millisecond, fileName);
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved