socket分段发送大文件的方法
请大家踊跃发表一件和贴代码。大量分分送上,up的也有分。
[解决办法]
将文件分段传送,每次传送8KB。
先定义一个单个数据包的最大长度
然后发送文件。如果大小超过单个包大小就拆分后发送。
接收段只需要把数据拼合起来就好了。
[解决办法]
幫頂吧···
[解决办法]
封包,定义包头包尾.
[解决办法]
我自己收集的方法,没有真正用过
private void SendFileStream(Socket socketStream, FileStream fs, byte[] byPack, string strFileName) { byte[] byHead = new byte[128]; byHead[0] = byPack[0]; byHead[1] = byPack[1]; byte[] byFileName = encodingGB.GetBytes(strFileName); byHead[2] = Convert.ToByte(byFileName.Length); byFileName.CopyTo(byHead, 3); if (socketStream != null) { SocketSendMessage(socketStream, byHead); } else { MessageBox.Show("socket"); return; } //socketStream.Send(byHead); byte[] byBody = new byte[PACKET_SIZE]; int nPackCount = Convert.ToInt32(byPack[0]) * Convert.ToInt32(byPack[1]); int nCurrentPack = 0; while (true) { if (socketStream != null) { SocketReceiveMessage(socketStream); } if (Convert.ToChar(byRec[0]) == 'E') { fs.Dispose(); fs.Close(); break; } else if (Convert.ToChar(byRec[0]) == 'S') { nCurrentPack = Convert.ToInt32(byRec[1]) * 256 + Convert.ToInt32(byRec[2]); fs.Seek((nCurrentPack - 1) * PACKET_SIZE, SeekOrigin.Begin); byBody = new byte[PACKET_SIZE]; if ((nCurrentPack == nPackCount) && (nLastPackSize != 0)) { fs.Read(byBody, 0, nLastPackSize); } else { fs.Read(byBody, 0, PACKET_SIZE); } if (socketStream != null) { SocketSendMessage(socketStream, byBody); } else { MessageBox.Show("socket"); return; } } } }
[解决办法]
public struct FilePack
{
/// <summary>
/// 数据包大小
/// </summary>
public ushort PackSize;
/// <summary>
/// 文件GUID
/// </summary>
public byte[] FileGuid; //16
///// <summary>
///// 包数据SHA1验证 ...
///// </summary>
//public byte[] PackSHA1;
/// <summary>
/// 包总数量
/// </summary>
public ushort PackCount;
/// <summary>
/// 包号
/// </summary>
public ushort PackIndex;
/// <summary>
/// 包数据
/// </summary>
public byte[] PackData;
}
这样发啊...
------解决方案--------------------
int port = 1234;
int port = 1234;
IPAddress ip = IPAddress.Parse("127.0.0.1");
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(ip,port);
//socket.Blocking = false;
socket.Bind(iep);
socket.Listen(10);
Console.WriteLine("start......");
try
{
for (int i = 0; i < 10;i++ )
{
}
}
catch
{
Console.WriteLine("异常!");
socket.Close();
}
接收端
private void Receive(Socket socket)
{
NetworkStream ns = new NetworkStream(socket);
FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
bool isRead = true;
while (isRead)
{
int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);
int datanum = 0;
datanum = BitConverter.ToInt32(this._receiveBuf, 0); //从buffer中的前4个字节读出count
if (datanum > 0) //确定每次要接受多少字节数
{
fs.Write(this._receiveBuf, 4, datanum);
}
else //如果接受字节数为0 就推出
{
isRead = false;
}
}
this.txtFile.Text = "文件传输成功";
fs.Close();
}
---------------------
发送端
private void btSend_Click(object sender, System.EventArgs e)
{
if (this._isConnect)
{
_ns = _tc.GetStream();
string path = this.txtPath.Text.Trim();
FileStream fs = new FileStream(path, FileMode.Open);
int sendCount = 0;
byte[] countbuffer = null;
byte[] clientbuffer = new byte[1004];
while (sendCount < fs.Length && _ns.CanWrite)
{
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //读出要发送的数据
countbuffer = BitConverter.GetBytes(count);
countbuffer.CopyTo(clientbuffer,0);
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //写入网络流
sendCount += count;
}
countbuffer = BitConverter.GetBytes(0); //发送完文件后 发送count = 0
this._ns.Write(countbuffer, 0, countbuffer.Length); //使接收端停止
_ns.Close();
fs.Close();
}
}
你为什么不把这两种方案结合在一起呢?
首先把文件的总长度和每次发送的大小先发送出去,等接收端接受并分析,然后开始。
比如每次发送4K(这是操作系统文件管理中使用到的最小文件大小,你可以看看你系统中的任何一个文件,占用空间都是4K的整数倍),
最后一次可能会少与4K,但是接受方是可以计算出来的。
必要时,你可以使用多线程,分段发送,接收端收集后分段组合,这还要多使用一个段号码。
socket是最底层的类,传输效率最高!
对于你说的异步操作,一句话说不清楚,基本上可以用“非阻塞模型”来概括,就是调用后立马返回,不是等到操作完成后才返回!
打个比方:阻塞模型
while(isok)
{
readdata(data);//从文件读数据
send(data); //一直等到data发送完毕后才返回,其实这期间本来可以进行下一次读操作
//影响了效率。
if(读完)
isok=false;
else
isok=true;
}
非阻塞模型,可以在发送过程中进行读取操作,提高了效率。
当然,在第二次发送前,必须等待第一次发送操作完成才行,需要检测和控制!
while (sendCount < fs.Length && _ns.CanWrite)
{
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //读出要发送的数据
countbuffer = BitConverter.GetBytes(count);
countbuffer.CopyTo(clientbuffer,0);
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //写入网络流
sendCount += count;
}
有点乱:你每次读取1000还是1004??不是前四个字节是长度吗?为什么从文件里读取1004个字节啊?
BeginReceiveFrom 方法启动从远程主机异步读取无连接数据报的操作。调用 BeginReceiveFrom 方法将使您能够在单独的执行线程中接收数据。
您可以创建一个实现 AsyncCallback 委托的回调方法并将它的名称传递给 BeginReceiveFrom 方法。为此,您的 state 参数至少必须包含用于通信的已连接或默认 Socket。如果您的回调需要更多信息,则可以创建一个小型类来保存 Socket 和其他必需的信息。通过 state 参数将此类的一个实例传递给 BeginReceiveFrom 方法。
回调方法应调用 EndReceiveFrom 方法。当应用程序调用 BeginReceiveFrom 时,系统将会使用单独的线程来执行指定的回调方法,并将在 EndReceiveFrom 上一直阻止到 Socket 读取数据或引发异常为止。如果想要在调用 BeginReceiveFrom 方法后使原始线程阻止,请使用 WaitHandle.WaitOne。当需要原始线程继续执行时,请在回调方法中调用 T:System.Threading.ManualResetEvent 的 Set 方法。有关如何编写 callback 方法的其他信息,请参见 Callback 示例。
注意
在调用 BeginReceiveFrom 之前,必须使用 Bind 方法显式地将 Socket 绑定到本地终结点,否则 BeginReceiveFrom 将会引发 SocketException。
该方法将数据读入 buffer 参数中,并捕获从其发送数据的远程主机终结点。有关如何检索此终结点的信息,请参考 EndReceiveFrom。如果打算从未知主机或多个主机异步接收无连接的数据报,则最适合使用此方法。在这些情况下,BeginReceiveFrom 将会读取本地网络缓冲区接收到的第一个排队数据报。如果您接收到的数据报大于 buffer 的大小,则 BeginReceiveFrom 方法将在 buffer 中尽可能多地填充消息内容,并引发 SocketException。如果您使用的是不可靠协议,多余的数据将会丢失。而如果当前使用的是可靠协议,则服务提供程序将保留多余的数据,而且通过使用一个足够大的缓冲区调用 BeginReceiveFrom 方法来检索这些数据。
虽然 BeginReceiveFrom 是用于无连接协议的,但您同样可以使用面向连接的协议。如果选择这样做,则必须通过调用 Connect / BeginConnect 方法来建立远程主机连接,或者调用 Accept 或 BeginAccept 方法来接受传入的连接请求。如果在建立连接或接受连接之前就调用了 BeginReceiveFrom 方法,则您将得到 SocketException。您也可以在调用 BeginReceiveFrom 方法之前,为无连接协议建立默认远程主机。在上述任何一种情况下,BeginReceiveFrom 方法都会忽略 remoteEP 参数,并且只从已连接的或默认的远程主机接收数据。
对于面向连接的套接字,BeginReceiveFrom 将读取所有可用的数据,直到达到 size 参数所指定的字节数。
若要取消挂起的 BeginReceiveFrom,请调用 Close 方法。
下面的代码示例异步接收来自远程主机的无连接数据报。
BeginReceiveFrom 方法启动从远程主机异步读取无连接数据报的操作。调用 BeginReceiveFrom 方法将使您能够在单独的执行线程中接收数据。
您可以创建一个实现 AsyncCallback 委托的回调方法并将它的名称传递给 BeginReceiveFrom 方法。为此,您的 state 参数至少必须包含用于通信的已连接或默认 Socket。如果您的回调需要更多信息,则可以创建一个小型类来保存 Socket 和其他必需的信息。通过 state 参数将此类的一个实例传递给 BeginReceiveFrom 方法。
[解决办法]
先说麻烦事吧 我也做过,要是单个文件还好办定义好 包头 包体 包头里边是文件信息:文件名、文件大小等等
要是文件夹就麻烦了,接收方还要创建相应的文件夹和子目录,我是没实现 ^_^
最后是异常处理,断点续传,高级点能实现暂停功能
[解决办法]
建议一次不要申请太大的内存,每次固定读4k(或8k),读了就写入文件流,循环利用那个缓冲区。其他的文件流和那个缓冲区可以交给系统自己管理。只要你不要一次申请太多就好了。
[解决办法]
mark
[解决办法]
顶个先,
[解决办法]
上边的代码好长好长啊。。
其实我想简单说说思路。 楼主能提这样的问题,说明楼主对TCP或者UDP的通信实现已经完全没问题了。
要传递大文件,无非就是分块,之后考虑续传。
块分的多大 要考虑三方面, 一是你网络环境(速度啊、稳定性啊) 一个是你的业务需要(频率、数量等) 再就是你的性能要求。
块越大, 并发性,灵活性就差一些。 块越小,传输效率就差一些。
业务上分块 传输上 分帧, 加序号,设缓存, 愿意的话加验证, 最好加上时间戳。
[解决办法]
顶楼上的 说法,我觉得还是要看业务的需求
[解决办法]
例子下载
[解决办法]
思路估计大家都有。而且还可以多线程传。。。
[解决办法]
up
[解决办法]
先定义一个单个数据包的最大长度
然后发送文件。如果大小超过单个包大小就拆分后发送。
[解决办法]
分线程读取数据,然后在线程中进行发送;
接收到后直接写到文件中的相应位置即可;
这样可以保证速度能够尽量的快。
具体线程数量视实际情况而定,一般定个10个线程应该没问题吧。
[解决办法]
这方面的资料可以去www.cnblogs.com看看。。。
[解决办法]
mark下
------解决方案--------------------
标记
[解决办法]
14楼答的不错,lz细心看看
up