1. 程式人生 > >C#實戰026:socket實現單檔案傳輸

C#實戰026:socket實現單檔案傳輸

    實現簡單的資訊通訊,接下來我們要繼續來是實現檔案的傳輸,同樣這次先試試單個簡單的小檔案傳輸,首先先說說原理,這次我們先對檔案進行檔名獲取,將檔名以資訊傳輸的形式的先傳遞給服務端,目的是讓伺服器知道我們要傳送的檔名及檔案型別,接著再來發送檔案,這裡我們需要將檔案轉化成位元組形式傳送,然後再把接收到的位元組寫入到檔案中。

這裡用到了Forms視窗程式來獲取需要傳送的檔案,大家可以參考:C#實戰025:控制檯呼叫Forms視窗程式

客戶端程式碼(已經詳細的解釋了每行程式碼的意思了):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Windows.Forms;


namespace SocketClient
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            SocketClient();
        }
        public static string serverIp = "127.0.0.1";//設定服務端IP
        public static int serverPort = 8888;//服務端埠
        public static Socket socketClient;//定義socket
        public static Thread threadClient;//定義執行緒
        public static byte[] result = new byte[1024];//定義快取
        public static void SocketClient()
        {
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立一個socket的物件
            IPAddress ip = IPAddress.Parse(serverIp);//獲取伺服器IP地址
            IPEndPoint point = new IPEndPoint(ip, serverPort);//獲取埠
            try
            {
                socketClient.Connect(point);//連結伺服器IP與埠
                Console.WriteLine("連線伺服器中.....");
            }
            catch (Exception)
            {
                Console.WriteLine("與伺服器連結失敗!!!");
                return;
            }
            Console.WriteLine("與伺服器連結成功!!!");
            try
            {
                Thread.Sleep(1000);    //等待1秒鐘  
                //通過 socketClient 向伺服器傳送資料
                string sendMessage = "已成功接到SocketClient傳送的訊息";//傳送到服務端的內容
                byte[] send = Encoding.UTF8.GetBytes(sendMessage);//Encoding.UTF8.GetBytes()將要傳送的字串轉換成UTF8位元組陣列
                byte[] SendMsg = new byte[send.Length + 1];//定義新的位元組陣列
                SendMsg[0] = 0;//將陣列第一位設定為0,來表示傳送的是訊息資料  
                Buffer.BlockCopy(send, 0, SendMsg, 1, send.Length);//偏移複製位元組陣列
                socketClient.Send(SendMsg);  //將接受成功的訊息返回給SocketServer伺服器 
                Console.WriteLine("傳送完畢:{0}", sendMessage);
            }
            catch
            {
                socketClient.Shutdown(SocketShutdown.Both);//禁止Socket上的傳送和接受
                socketClient.Close();//關閉Socket並釋放資源
            }
            try
            {
                OpenFileDialog open = new OpenFileDialog();//建立OpenFileDialog例項,方便開啟選取檔案對話方塊
                open.Multiselect = true;//是否允許多選
                if (open.ShowDialog() == DialogResult.OK)//按下確定選擇的按鈕
                {
                    string fileName = open.FileName;  //獲取選取檔案的檔案路徑及檔名
                    FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);//建立檔案流,用來讀取資料
                    string fileN = Path.GetFileName(fileName);//提取檔名
                    byte[] arrMsg = Encoding.UTF8.GetBytes(fileN);//將要傳送的字串轉換成UTF8位元組陣列
                    byte[] arrSendMsg = new byte[arrMsg.Length + 1];//定義新的位元組陣列
                    arrSendMsg[0] = 0;//將陣列第一位設定為0,來表示傳送的是訊息資料  
                    Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);//偏移複製位元組陣列
                    socketClient.Send(arrSendMsg); //將接受成功的訊息返回給SocketServer伺服器 
                    byte[] arrFile = new byte[fs.Length]; //定義快取控制元件,長度為檔案長度
                    int length = fs.Read(arrFile, 0, arrFile.Length);//將檔案讀入快取空間
                    byte[] SendarrFile = new byte[length + 1];//定義新的位元組陣列
                    SendarrFile[0] = 1;//將陣列第一位設定為1,來表示傳送的是檔案資料
                    Buffer.BlockCopy(arrFile, 0, SendarrFile, 1, length);//偏移複製位元組陣列
                    socketClient.Send(SendarrFile);//將讀取成功的檔案傳送給SocketServer伺服器 
                    Console.WriteLine("檔案傳送完畢!!!!");
                }
            }
            catch (Exception)
            {
                socketClient.Shutdown(SocketShutdown.Both);//禁止Socket上的傳送和接受
                socketClient.Close();//關閉Socket並釋放資源
            }
            socketClient.Close();//關閉Socket並釋放資源
            Console.ReadLine();
        }
    }

}

伺服器端程式碼(已經詳細的解釋了每行程式碼的意思了): 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Windows.Forms;

namespace SocketServer
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            SocketServer();
        }
        public static string serverIp = "127.0.0.1";//設定服務端IP
        public static int serverPort = 8888;//服務端埠
        public static Socket socketServer;//定義socket
        public static Thread threadWatch;//定義執行緒
        public static byte[] result = new byte[1024 * 1024 * 2];//定義快取
        public static string fileName;//獲取檔名
        public static void SocketServer()
        {
            socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立一個socket的物件
            IPAddress ip = IPAddress.Parse(serverIp);//獲取伺服器IP地址
            IPEndPoint point = new IPEndPoint(ip, serverPort);//獲取埠
            try
            {
                socketServer.Bind(point);//繫結IP地址及埠
            }
            catch (Exception ex)
            {
                Console.WriteLine("繫結IP時出現異常:" + ex.Message);
                return;
            }
            socketServer.Listen(100);//開啟監聽並設定最多10個排隊連線請求
            threadWatch = new Thread(WatchConnect);//建立一個監聽程序
            threadWatch.IsBackground = true;//後臺啟動
            threadWatch.Start();//執行
            Console.WriteLine("伺服器{0}監聽啟動成功!", socketServer.LocalEndPoint.ToString());
            Console.ReadLine();
        }
        public static void WatchConnect()
        {
            while (true)
            {
                Socket watchConnect = socketServer.Accept();//接收連線並返回一個新的Socket
                watchConnect.Send(Encoding.UTF8.GetBytes("伺服器連線成功"));//在客戶端顯示"伺服器連線成功"提示
                Thread threadwhat = new Thread(ReceiveMsg);//建立一個接受資訊的程序
                threadwhat.IsBackground = true;//後臺啟動
                threadwhat.Start(watchConnect);//有傳入引數的執行緒
            }
        }
        public static void ReceiveMsg(object watchConnect)
        {
            Socket socketClient = (Socket)watchConnect;
            while (true)
            {
                int num = -1;//初始化num
                string reveiceName;//定義字串
                try
                {
                    num = socketClient.Receive(result);//獲取客戶端資訊
                    reveiceName = Encoding.UTF8.GetString(result, 0, num);//把從0到num的位元組變成String
                }
                catch (SocketException ex)
                {
                    Console.WriteLine("異常:" + ex.Message + ", RemoteEndPoint: " + socketClient.RemoteEndPoint.ToString());
                    break;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("異常:" + ex.Message);
                    break;
                }
                try
                {
                    if (reveiceName[0] == 0)//判斷陣列第一個值,如果為0則說明傳的是資訊
                    {
                        fileName = Encoding.UTF8.GetString(result, 1, num - 1);//提取位元組資訊並轉換成String
                        Console.WriteLine("接收客戶端的訊息:{0}", fileName);
                    }
                    if (reveiceName[0] == 1)//判斷陣列第一個值,如果為0則說明傳的是檔案
                    {
                        SaveFileDialog save = new SaveFileDialog();//建立SaveFileDialog例項
                        string spath = @"C:\Users\admin\Desktop";//制定儲存路徑
                        string fullPath = Path.Combine(spath, fileName);//獲取儲存路徑及檔名
                        FileStream filesave = new FileStream(fullPath, FileMode.Create, FileAccess.Write);//建立檔案流,用來寫入資料
                        filesave.Write(result, 1, num - 1);//將資料寫入到檔案中
                        filesave.Close();
                        Console.WriteLine("儲存成功!!!");
                    }
                }
                catch (Exception ex )
                {

                    Console.WriteLine(ex.Message );
                }
              
            }
            
        }
    }
}