C#實戰026:socket實現單檔案傳輸
阿新 • • 發佈:2018-12-06
實現簡單的資訊通訊,接下來我們要繼續來是實現檔案的傳輸,同樣這次先試試單個簡單的小檔案傳輸,首先先說說原理,這次我們先對檔案進行檔名獲取,將檔名以資訊傳輸的形式的先傳遞給服務端,目的是讓伺服器知道我們要傳送的檔名及檔案型別,接著再來發送檔案,這裡我們需要將檔案轉化成位元組形式傳送,然後再把接收到的位元組寫入到檔案中。
這裡用到了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 ); } } } } }