C# socket编程第四篇

第三篇里已经实现了文件的传输,但是在第三篇里,传输的文件是用一个包传过去的,如果文件大点的话,就无法实现了,今天我们来讲如何将大文件分包来处理。既然一个大文件不能一次传,那就要多次传了,既然是多次,那就要分包了。先把demo贴出,程序中都有注释。

服务端:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net.Sockets;

using System.Net;

using System.IO;

namespace FileReceiveControl

{

public class FileOutPackets

{

public void GetFileOutPackets()

{

try

{

Console.WriteLine("this is server");

int Port = 8001;

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, Port);

EndPoint ep = (EndPoint)ipep;

Socket sc = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

sc.Bind(ep);

IPEndPoint ipepClient = new IPEndPoint(IPAddress.Any, 0);

EndPoint epClient = (EndPoint)ipepClient;

int Rec;

byte[] Bytes = new byte[1024];

//=====获取文件名

Rec = sc.ReceiveFrom(Bytes, ref epClient);

string FileName = Encoding.ASCII.GetString(Bytes, 0, Rec);

//=====向客服端 发送接收到的信号

Bytes = Encoding.ASCII.GetBytes("1");

sc.SendTo(Bytes, epClient);

//======获取文件 bytes 大小

Bytes = new byte[1024];

Rec = sc.ReceiveFrom(Bytes, ref epClient);

//=====向客服端 发送接收到的信号

//Bytes = Encoding.ASCII.GetBytes("2");

//sc.SendTo(Bytes, epClient);

//=======获取fs bytes总的大小

int FileByteLength = int.Parse(Encoding.ASCII.GetString(Bytes, 0, Rec));

//=======获取总的包数量

Bytes = new byte[1024];

Rec = sc.ReceiveFrom(Bytes, ref epClient);

//=======获取总的包数量

int PacketNum = int.Parse(Encoding.ASCII.GetString(Bytes, 0, Rec));

Console.WriteLine("packetNum is " + PacketNum);

//====获取最后一个包的大小

Bytes = new byte[1024];

Rec = sc.ReceiveFrom(Bytes, ref epClient);

int FinalPacketSize = int.Parse(Encoding.ASCII.GetString(Bytes, 0, Rec));

string TempPath = @"E:\" + FileName + ".temp";

FileStream fs = new FileStream(TempPath, FileMode.OpenOrCreate, FileAccess.Write);

//======循环 接收

for (int i = 0; i < PacketNum; i++)

{

byte[] Data = new byte[8192];

Rec = sc.ReceiveFrom(Data, ref epClient);

fs.Write(Data, 0, 8192);

fs.Flush();

Console.WriteLine("this is " + (i + 1) + " packet");

}

if (FinalPacketSize != 0)

{

byte[] data = new byte[FinalPacketSize];

Rec = sc.ReceiveFrom(data, ref epClient);

fs.Write(data, 0, FinalPacketSize);

fs.Flush();

}

fs.Close();

sc.Close();

FileStream FsMove = new FileStream(TempPath, FileMode.Open, FileAccess.Read);

string Path = TempPath.Remove(TempPath.Length - 5, 5);

byte[] ByteFile = new byte[FsMove.Length];

FsMove.Read(ByteFile, 0, (int)FsMove.Length);

File.WriteAllBytes(Path, ByteFile);

FsMove.Close();

File.Delete(TempPath);

Console.WriteLine("receive is over");

//===========死循环 方便调试 避免直接退出

while (true)

{

}

}

catch (Exception ex)

{

Console.WriteLine(ex.ToString());

}

}

}

}

客户端:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net;

using System.Net.Sockets;

using System.IO;

using System.Threading;

namespace FileDistributeControl

{

public class FileOutPackets

{

public void GetFileOutPackets()

{

Console.WriteLine("this is client");

int Port=8001;

string Ip="192.168.1.20";

IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(Ip), Port);

EndPoint ep = (EndPoint)ipep;

Socket sc = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);

string path = @"F:\1.jpg";

FileInfo fino = new FileInfo(path);

IPEndPoint ipepClient = new IPEndPoint(IPAddress.Any,0);

EndPoint epClient = (EndPoint)ipepClient;

int Rec,Rtn;

byte[] Bytes=new byte[1024];

//=========发送 文件名

sc.SendTo(Encoding.ASCII.GetBytes(fino.Name),ep);

Rec = sc.ReceiveFrom(Bytes,ref epClient);

Rtn=int.Parse(Encoding.ASCII.GetString(Bytes,0,Rec));

if (Rtn == 1)

{

Console.WriteLine("this file name send successful");

FileStream fs = new FileStream(path,FileMode.Open,FileAccess.Read);

//=======取得最后一个数据包前的数据包总数 (int)将一个浮点数 转整型,只会四舍,不会五入

//=======1k==1024B==1024*8b 1k等于2的10次方字节,一个字节等于8位

int PacketNum = (int)(fs.Length /(long)8192);

int EndPacket = (int)(fs.Length - PacketNum * 8192);

//=======最后一个包有可能是0

int TotalPacket;

if (EndPacket == 0)

{

TotalPacket = PacketNum;

}

else

{

TotalPacket = PacketNum + 1;

}

//=======发送总 的数据包 etc

sc.SendTo(Encoding.ASCII.GetBytes(fs.Length.ToString()), ep);

sc.SendTo(Encoding.ASCII.GetBytes(PacketNum.ToString()), ep);

sc.SendTo(Encoding.ASCII.GetBytes(EndPacket.ToString()),ep);

//=======循环发送

Console.WriteLine("packetNum is "+PacketNum);

for (int i = 0; i < PacketNum; i++)

{

byte[] data = new byte[8192];

fs.Read(data, 0, 8192);

sc.SendTo(data,ep);

Console.WriteLine("this is "+(i+1)+" packet");

Thread.Sleep(300);

}

Console.WriteLine("this for is over");

//=======发送最后一个包

if (EndPacket != 0)

{

byte[] finallData=new byte[EndPacket];

fs.Read(finallData,0,EndPacket);

sc.SendTo(finallData,ep);

Console.WriteLine("this is final packet");

}

Console.WriteLine("send over");

}

else

{

//=======返回值不等于1 重新发送

sc.SendTo(Encoding.ASCII.GetBytes(fino.Name),ep);

}

while (true)

{ }

}

}

}

这样就可以把一个大文件分成很多个包来进行发送了。这里需要注意的是,循环发送的时候需要休眠段时间,如果没有sleep这条语句,那么在服务端无法完整的收完每一个包。至于为什么一次性发完无法收取完,我现在也解释不了,在研究中...希望下一遍的时候可以解决这些问题..