1.Net.cs using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SocketIM { ////// Net : 提供靜態方法,對常用的網絡操作進行封裝 public class Net { public class ObjectState { public string fileName { get; set; } public Socket workSocket { get; set; } public Thread workThread { get; set; } } private Net() { } ////// 向遠程主機發送數據 //////要發送數據且已經連接到遠程主機的 Socket///待發送的數據///發送數據的超時時間,以秒為單位,可以精確到微秒///0:發送數據成功;-1:超時;-2:發送數據出現錯誤;-3:發送數據時出現異常////// 當 outTime 指定為-1時,將一直等待直到有數據需要發送 public static int SendData(Socket socket, byte[] buffer, int outTime) { if (socket == null || socket.Connected == false) { throw new ArgumentException("參數socket 為null,或者未連接到遠程計算機"); } if (buffer == null || buffer.Length == 0) { throw new ArgumentException("參數buffer 為null ,或者長度為 0"); } int flag = 0; try { int totalLen = buffer.Length; int sndLen = 0; while (true) { if ((socket.Poll(outTime * 100, SelectMode.SelectWrite) == true)) { // 收集了足夠多的傳出數據后開始發送 sndLen = socket.Send(buffer, sndLen, totalLen, SocketFlags.None); totalLen -= sndLen; if (totalLen == 0) { // 數據已經全部發送 flag = 0; break; } else { if (sndLen > 0) { // 數據部分已經被發送continue; } else { // 發送數據發生錯誤 flag = -2; break; } } } else { // 超時退出 flag = -1; break; } } } catch (SocketException e) { flag = -3; } return flag; } ////// 向遠程主機發送文件 //////要發送數據且已經連接到遠程主機的 socket///待發送的文件名稱///文件發送時的緩沖區大小///發送緩沖區中的數據的超時時間///0:發送文件成功;-1:超時;-2:發送文件出現錯誤;-3:發送文件出現異常;-4:讀取待發送文件發生錯誤////// 當 outTime 指定為-1時,將一直等待直到有數據需要發送 public static int SendFile(string ip, int port, string fileName, int maxBufferLength, int outTime) { IPAddress address = IPAddress.Parse(ip); IPEndPoint endpoint = new IPEndPoint(address, port); //創建服務端負責監聽的套接字,參數(使用IPV4協議,使用流式連接,使用TCO協議傳輸數據) Thread.Sleep(1500); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(endpoint); if (socket.Connected) { Console.WriteLine(socket.RemoteEndPoint + "連接成功"); } if (fileName == null || maxBufferLength <= 0) { throw new ArgumentException("待發送的文件名稱為空或發送緩沖區的大小設置不正確."); } int flag = 0; try { FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); long fileLen = fs.Length; // 文件長度 long totalLen = fileLen; // 未讀取部分 int readLen = 0; // 已讀取部分 byte[] buffer = null; if (fileLen <= maxBufferLength) { /* 文件可以一次讀取*/ buffer = new byte[fileLen]; readLen = fs.Read(buffer, 0, (int)fileLen); flag = SendData(socket, buffer, outTime); } else { /* 循環讀取文件,並發送 */ while (totalLen != 0) { if (totalLen < maxBufferLength) { buffer = new byte[totalLen]; readLen = fs.Read(buffer, 0, Convert.ToInt32(totalLen)); } else { buffer = new byte[maxBufferLength]; readLen = fs.Read(buffer, 0, maxBufferLength); } if ((flag = SendData(socket, buffer, outTime)) < 0) { break; } totalLen -= readLen; } } fs.Flush(); fs.Close(); socket.Shutdown(SocketShutdown.Both); socket.Close(); } catch (IOException e) { flag = -4; } if (flag == 0) { Console.WriteLine(fileName + "文件發送成功"); socket.Close(); Console.WriteLine("連接關閉"); } else { Console.WriteLine(fileName + "文件發送失敗,i=" + flag); } return flag; } private static void WatchConnecting(object info) { ObjectState state = (ObjectState)info; Socket socketWatch = state.workSocket; while (true)//持續不斷的監聽客戶端的請求 { //開始監聽 客戶端連接請求,注意:Accept方法,會阻斷當前的線程 Socket connection = socketWatch.Accept(); if (connection.Connected) { //創建通信線程 Thread thradRecMsg = new Thread(RecMsg); state.workSocket = connection; state.workThread = thradRecMsg; thradRecMsg.IsBackground = true; thradRecMsg.Start(state); } } } ////// 接收消息 private static void RecMsg(object socketClientPara) { ObjectState state = (ObjectState)socketClientPara; string fileName = state.fileName;//$@"d:HQ.dat";//獲得用戶保存文件的路徑 Socket socketClient = state.workSocket; FileStream fs = null; while (true) { //定義一個接受用的緩存區(100M字節數組) //將接收到的數據存入arrMsgRec數組,並返回真正接受到的數據的長度 if (socketClient.Connected) { try { //因為終端每次發送文件的最大緩沖區是512字節,所以每次接收也是定義為512字節 byte[] buffer = new byte[512]; int size = 0; //統計實際文件大小 long len = 0; //創建文件流,然后讓文件流來根據路徑創建一個文件 fs = new FileStream(fileName, FileMode.Append); DateTime oTimeBegin = DateTime.Now; //從終端不停的接受數據,然后寫入文件里面,只到接受到的數據為0為止,則中斷連接 while ((size = socketClient.Receive(buffer, 0, buffer.Length, SocketFlags.None)) > 0) { fs.Write(buffer, 0, size); len += size; } DateTime oTimeEnd = DateTime.Now; TimeSpan oTime = oTimeEnd.Subtract(oTimeBegin); fs.Flush(); fs.Close(); socketClient.Shutdown(SocketShutdown.Both); socketClient.Close(); Console.WriteLine("文件保存成功:" + fileName); Console.WriteLine("接收文件用時:" + oTime.ToString() + ",文件大小:" + len / 1024 + "kb"); } catch (Exception ex) { if (fs != null) { fs.Dispose(); } if (File.Exists(fileName)) { File.Delete(fileName); } Console.WriteLine(socketClient.RemoteEndPoint + "下線了"); break; } } else { } } } public static void AcceptFile(string ip, int port, string fileName) { //創建服務端負責監聽的套接字,參數(使用IPV4協議,使用流式連接,使用Tcp協議傳輸數據) Socket socketListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketListen.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); //獲取Ip地址對象 IPAddress address = IPAddress.Parse(ip); //創建包含Ip和port的網絡節點對象 IPEndPoint endpoint = new IPEndPoint(address, port); //將負責監聽的套接字綁定到唯一的Ip和端口上 socketListen.Bind(endpoint); //設置監聽隊列的長度 socketListen.Listen(10); connectDone.Set(); ObjectState state = new ObjectState(); //創建負責監聽的線程,並傳入監聽方法 Thread threadWatch = new Thread(WatchConnecting); state.fileName = fileName; state.workSocket = socketListen; state.workThread = threadWatch; threadWatch.IsBackground = true;//設置為后台線程 threadWatch.Start(state);//開始線程 } public static void CloseTcpSocket(Thread threadWatch, Socket socketWatch) { threadWatch.Abort(); socketWatch.Close(); Console.WriteLine("服務器關閉監聽"); } public static ManualResetEvent connectDone = new ManualResetEvent(false); public static void FileMove(string ip, int port, string fromPath, string toPath) { AcceptFile(ip, port, toPath); connectDone.WaitOne(); int i = SendFile(ip, port, fromPath, 512, 90000); Console.WriteLine("文件從" + fromPath + "到" + toPath + "移動成功!!!!"); } } } 2.調用代碼 private void button1_Click(object sender, EventArgs e) { //string topath = $@"d:HQ.dat"; //string frompath = $@"e:\HQ.dat"; //Net.FileMove("127.0.0.1", 11000, frompath,topath); string topath = $@"d:bb\HQ.dat"; string frompath = $@"d:aa\HQ.dat"; Net.FileMove("127.0.0.1", 11000, frompath, topath); }