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这条语句,那么在服务端无法完整的收完每一个包。至于为什么一次性发完无法收取完,我现在也解释不了,在研究中...希望下一遍的时候可以解决这些问题..

posted @ 2011-05-10 15:37  comeonfyz  阅读(1050)  评论(7编辑  收藏  举报