c#異步文件傳輸功能


服務器端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
namespace RecvFileServer
{
    /// <summary>
    /// 本文件主要處理多文件傳輸,首先做單文件傳輸,然后做多文件進行傳輸,今天完成對多文件發送.今天一定要寫完成對多文件傳輸.能夠進行測試成功
    /// </summary>

    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct SendFileMessage
    {
        
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public char[] fileName;
        /// <summary>
        /// 傳遞的包類型。1 代表發送要創建的文件,2. 代表為第一條數據,但不是最后一條數據 3. 為中間傳輸數據,並非為最后一個,4. 代表文件最后一條數據 5. 第一條也是最后一條文件數據
        /// 1. 首先能夠實現基本的單文件傳輸,單文件傳輸以后,便可以實現基本的多文件傳輸。
        /// </summary>
        public char typeMessage;
        //有效數據長度
        public int effDataLength;
        //有效數據
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
        public byte[] effData;
    }

    public class StateObject
    {
        // Client  socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1037;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        //在此處,每個socket有對應額的一個FileStream
    }

    public class AsynchronousSocketServer
    {
        public static   FileStream writefile;
        public static ManualResetEvent allDone = new ManualResetEvent(false);
        private static Socket serverSocket;
        public static void StartAsynchronousSocket()
        {
            Console.WriteLine("服務器啟動成功");
            IPAddress ipAddress = IPAddress.Parse("192.168.0.40");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8083);
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                serverSocket.Bind(ipEndPoint);
                serverSocket.Listen(1000);
                while (true)
                {
                    allDone.Reset();
                    serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
                    allDone.WaitOne();
                }
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public static void AcceptCallback(IAsyncResult ar)
        {
            //在此處輸出連接到的ip地址。當連接成功的時候,進行接收數據。handle指代的是連接到的client的socket
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);
            allDone.Set();
            StateObject states = new StateObject();
            states.workSocket = handler;
            handler.BeginReceive(states.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(RecvCallback), states);
        }

        public static void RecvCallback(IAsyncResult ar)
        {
            //在此處進行設置一下,將其中的放入進去
            String content = String.Empty;
            //獲取StateObject實例,並獲取StateObject中的socket
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;
            //從client socket接收數據
            int bytesRead = handler.EndReceive(ar);
            if (bytesRead > 0)
            {
                //判斷讀寫的數據是否完成。如果沒有,繼續讀寫,如何判斷是否接受完成呢?不能夠使用EOF呢
                if (bytesRead == 1037)
                {
                    //獲取傳輸到的數據,並轉為Unicode字符,以便支持中文.在此處進行開始獲取得到的數據,然后將獲取到的數據轉變為結構體類型
                    SendFileMessage sfm = new SendFileMessage();
                    sfm = (SendFileMessage)ByteToStruct(state.buffer, typeof(SendFileMessage));
                    Console.WriteLine(sfm.typeMessage);
                    //此處暫時把1去掉,改用在讀取第一次的時候進行創建
                    if (sfm.typeMessage == '1')
                    {

                    }
                   else  if (sfm.typeMessage == '2') //2 代表的是文件對應的第一次,需要打開對應的文件,是否需要在SocketState中進行呢?
                    {
                        //每個客戶端的連接可以的,依次放入其中呢。對每個客戶進行的連接,我們都需要設置並將其中的連接放入到里面。現在都先放入debug文件目錄下

                        String strPath = new String(sfm.fileName);
                        writefile = new FileStream(strPath + ".jpg", FileMode.OpenOrCreate);
                        writefile.Write(sfm.effData, 0, sfm.effDataLength);

                    }
                    else if (sfm.typeMessage == '3')
                    {
                        //如何根據其中的設置來進行。重新寫發送部分,先能夠成功接收一張<1K,=1K,>1K的文件;
                        writefile.Write(sfm.effData, 0, sfm.effDataLength);
                    }
                    else if (sfm.typeMessage == '4')
                    {
                       //代表最后一段數據,接受后寫入到文件中,然后將文件關閉.每次打開后關閉,打開后關閉.在此處判斷並將設置出來
                        writefile.Write(sfm.effData, 0, sfm.effDataLength);
                        writefile.Close();
                    }
                    else if (sfm.typeMessage =='5')
                    {
                        //如果此處為5代表文件大小小於1024字節,可以打開文件並進行存儲.打開文件,把獲取到的數據保存到新建的文件夾中.在此處接收成功。
                        //單文件進行傳輸,並將文件放入到里面
                        string strPath = new String(sfm.fileName);
                        writefile = new FileStream(strPath + ".jpg", FileMode.OpenOrCreate);
                        writefile.Write(sfm.effData, 0, sfm.effDataLength);
                        writefile.Close();
                    }
                }
            }
            //使用異步接收,繼續接收數據,將接收到的數據寫入到文件中去,並將數據放入文件中去。成功接收兩張圖片。一個是<1024,一個是>1024並且余數!=0
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(RecvCallback), state);
        }
        public static byte[] StructToBytes(object structObj, int size)
        {
            int len = Marshal.SizeOf(structObj);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //將結構體拷到分配好的內存空間。
            Marshal.StructureToPtr(structObj, structPtr, false);
            //從內存空間拷貝到byte 數組歐拉模型外的另一種相機模型UVN系統。編寫
            Marshal.Copy(structPtr, bytes, 0, size);
            //釋放內存空間,為每個部分做大量的要求,並把其中的要求放入進去,背面消除方式。FreeHGlobal.
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }

        public static object ByteToStruct(byte[] bytes, Type type)
        {
            int size = Marshal.SizeOf(type);
            if (size > bytes.Length)
            {
                return null;
            }
            //分配結構體空間,並把結構體AllocHGlobal(size);
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //將byte數組拷貝到分配好的內存空間
            Marshal.Copy(bytes, 0, structPtr, size);
            //將內存空間轉換為目標結構體
            object obj = Marshal.PtrToStructure(structPtr, type);
            //釋放內存空間。
            Marshal.FreeHGlobal(structPtr);
            return obj;
        }
    }
}

  客戶端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.InteropServices;
namespace SendFileClient
{
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct SendFileMessage
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] fileName;
//傳遞的包類型。1 代表發送要創建的文件,2. 代表為第一條數據 3. 為中間傳輸數據,並非為最后一個,4. 代表文件最后一條數據 5.第一條也是最后一條文件數據
public char typeMessage;
//有效數據長度
public int effDataLength;
//有效數據
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
public byte[] effData;
}

class AsynchronousSocketClient
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
public static Socket client;
public static void StartAsynchronousSocket()
{
IPAddress ipAddress = IPAddress.Parse("192.168.0.40");
IPEndPoint ipPoint = new IPEndPoint(ipAddress, 8083);
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(ipPoint, new AsyncCallback(ConnectCallBack), client);
allDone.WaitOne();
while (true)
{
allDone.Reset();
SendFile(client, "zhl.jpg", "20101112");
SendFile(client, "jnvc.jpg", "20101113");
allDone.WaitOne();
}
}

public static void ConnectCallBack(IAsyncResult args)
{
Socket client = (Socket)args.AsyncState;
client.EndConnect(args);
Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
allDone.Set();
}

public static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.Unicode.GetBytes(data);
// Begin sending the data to the remote device.此處發生錯誤?是否是因為其進行呢??
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}

public static void Send(Socket handler, byte[] byteData)
{
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}

private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}


public static void SendFile(Socket client, String filePath,String serverFileName)
{

byte[] sendByteMessage = new byte[1037];
FileInfo fileInfo = new FileInfo(filePath);
int fileSize = (int)(fileInfo.Length);
FileStream afile = new FileStream(filePath, FileMode.Open);
SendFileMessage sfm = new SendFileMessage();
byte[] sendDataByte = new byte[1037];
byte[] dataByte = new byte[1024];
int i = (int)fileSize / 1024;
int yu = (int)fileSize % 1024;

//< = 1024 byte,則一次性把文件發送到服務器端
//>1024 byte的 時候,余數為0和不為0的情況,如果余數為0
if (fileSize <= 1024)
{
//在此處寫入到2.jpg
afile.Seek(0, SeekOrigin.Begin);
afile.Read(dataByte, 0, fileSize);
sfm.effData = dataByte;
sfm.effDataLength = fileSize;

sfm.fileName = (serverFileName.ToCharArray());
sfm.typeMessage = '5';
sendDataByte = StructToBytes(sfm, 1037);
Send(client, sendDataByte);
afile.Close();
}
else
{
if (yu != 0)
{
//余數不為0,則把其中的數據放入其中
for (int j = 0; j < i; j++)
{
//重新為sendByteMessage賦值。文件數據大小必須要符合要求。不然會報錯。使用光照引擎來進行

sfm.fileName = serverFileName.ToCharArray();
if (j == 0)
{
sfm.typeMessage = '2';
sfm.fileName = serverFileName.ToCharArray();
sfm.effDataLength = 1024;
}
else
sfm.typeMessage = '3';
afile.Seek(j * 1024, SeekOrigin.Begin);
afile.Read(dataByte, 0, 1024);
sfm.effData = dataByte;
sendByteMessage = StructToBytes(sfm,1037);
Send(client, sendByteMessage);
//全部數據發送。一定是要再接收數據.判斷其中的數據,放入到里面中
}
int seekNum = i * 1024;
long operNum = (long)seekNum;
afile.Seek(operNum, SeekOrigin.Begin);
afile.Read(dataByte, 0, yu);
//在此處重新組合sfm,然后發送次文件到sfm
sfm.typeMessage='4';
//在此處要把sfm轉變為struct類型
sendByteMessage = StructToBytes(sfm, 1037);
Send(client, sendByteMessage);
afile.Close();
}
else
{
for (int j = 0; j < i; j++)
{
afile.Seek(j * 1024, SeekOrigin.Begin);
afile.Read(dataByte, 0, 1024);
}
afile.Close();
}
}
}
private static void AsynchronousFileSendCallback(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
client.EndSendFile(ar);
}

//當時怎么做的呢?的確是呢,可以呢?
public static byte[] StructToBytes(object structObj, int size)
{
int len = Marshal.SizeOf(structObj);
byte[] bytes = new byte[size];
IntPtr structPtr = Marshal.AllocHGlobal(size);
//將結構體拷到分配好的內存空間
Marshal.StructureToPtr(structObj, structPtr, false);
//從內存空間拷貝到byte數組
Marshal.Copy(structPtr, bytes, 0, size);
//釋放內存空間,基於8bit
Marshal.FreeHGlobal(structPtr);
return bytes;
}

public static object ByteToStruct(byte[] bytes, Type type)
{
int size = Marshal.SizeOf(type);
if (size > bytes.Length)
{
return null;
}
//分配結構體
IntPtr structPtr = Marshal.AllocHGlobal(size);
//將byte數組拷貝到分配好的內存空間
Marshal.Copy(bytes, 0, structPtr, size);
//將內存空間轉換為目標結構體
object obj = Marshal.PtrToStructure(structPtr,type);
//釋放內存空間 定向光源和點光源
Marshal.FreeHGlobal(structPtr);
return obj;
}
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM