程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#網絡編程(訂立協議和發送文件) - Part.4(4)

C#網絡編程(訂立協議和發送文件) - Part.4(4)

編輯:關於C語言

2.3 ProtocolHelper輔助類

這個類專用於將XML格式的協議映射為我們上面定義的強類型對象,這裡我沒有加入try/catch異常處 理,因為協議對用戶來說是不可見的,而且客戶端應該總是發送正確的協議,我覺得這樣可以讓代碼更加 清晰:

public class ProtocolHelper {

    private XMLNode fileNode;
    private XMLNode root;

    public ProtocolHelper(string protocol) {
        XmlDocument doc = new XMLDocument();
        doc.LoadXML(protocol);
        root = doc.DocumentElement;
        fileNode = root.SelectSingleNode("file");
    }

    // 此時的protocal一定為單條完整protocal
    private FileRequestMode GetFileMode() {
        string mode = fileNode.Attributes["mode"].Value;
        mode = mode.ToLower();
        if (mode == "send")
            return FileRequestMode.Send;
        else
            return FileRequestMode.Receive;
    }

    // 獲取單條協議包含的信息
    public FileProtocol GetProtocol() {
        FileRequestMode mode = GetFileMode();
        string fileName = "";
        int port = 0;

        fileName = fileNode.Attributes["name"].Value;
        port = Convert.ToInt32(fileNode.Attributes["port"].Value);

        return new FileProtocol(mode, port, fileName);
    }
}

OK,我們又耽誤了點時間,下面就讓我們進入正題吧。

3.客戶端發送數據

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 wapper = new RemoteClient(clIEnt);
            wapper.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("
Reading 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);        // 清空緩存,避 免髒讀

            // 獲取protocol數組
            string[] protocolArray = handler.GetProtocol(msg);
            foreach (string pro in protocolArray) {
                // 這裡異步調用,不然這裡可能會比較耗時
                ParameterizedThreadStart start =
                    new ParameterizedThreadStart(handleProtocol);
                start.BeginInvoke(pro, null, null);
            }

            // 再次調用BeginRead(),完成時調用自身,形成無限循環
            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);      // 捕獲異常時退出程序
        }
    }

    // 處理protocol
    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) {
        // 獲取遠程客戶端的位置
        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]; // 每次收1KB
        FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write);

        // 從緩存buffer中讀入到文件流中
        int bytesRead;
        int totalBytes = 0;
        do {
            bytesRead = streamToClIEnt.Read(buffer, 0, BufferSize);
            fs.Write(buffer, 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