大家好,我是一名大四的学生。最近在做毕设,遇到了在c#中socket传输大文件的问题。
我的大体思路有两个(参考网上的资料)
----------------------
(1) 个人认为效率比较低
连接..
发送第一个字节块...
等待确认...(接收确认信息)
确认
发送第二个字节块...
等待确认...
确认
发送第三个.....
....
(2)个人认为效率比较高
发送端一直写入网络流
接收端一直读取网络流
----------------------
我在每个字节块的前面加入了一个int型的变量,它表示每次发送文件数据的长度
我根据思路(2)写了代码
如下
----------------------
接收端
[code]
private void Listener() //开始监听传输请求
{
IPHostEntry ipHostInfo =Dns.Resolve(System.Net.Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
this._ls =new TcpListener (ipAddress,6688);
this._ls .Start ();
while(true)
{
Socket socket=this._ls .AcceptSocket ();
this.txtConnect .Text =socket.RemoteEndPoint .ToString ();
Receive(socket); //调用接受文件函数
}
}
//我在每个字节块的前面加入了一个int型的变量,它表示每次发送文件数据的长度
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);
if (datanum > 0) //如果传输的文件字节数>0 证明还有数据没有传输完
{
fs.Write(this._receiveBuf, 4, datanum);
fs.Flush();
}
else //datanum = 0 ,文件发送完毕
{
isRead = false;
}
}
this.txtFile.Text = "文件传输成功";
fs.Close();
}[/code]
----------------------
发送端
[code]
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); //将count加入数组首部
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //写入网络流
sendCount += count;
}
countbuffer = BitConverter.GetBytes(0); //发送文件完后,读出字节数为0
this._ns.Write(countbuffer, 0, countbuffer.Length);
_ns.Close();
fs.Close();
}
}
[/code]
----------------------
我发现有时能够成功,有时却陷入死循环,比如我传输2k的txt,结果很长时间都没有停止,我中断后发现生成了200M的txt
实在搞不懂是为什么,请大家帮我分析分析.
-------------------------------
关于思路(1)我不会控制socket和相对应的networkstream
比如说发送端发送数据后,要等待接收端的确认信息
怎样让发送端停止发送数据来等待确认信息
接收到后又怎样重新发送数据
说简单一点就是发送端和接收端有序的操作网络流的问题
请大家多多指点
-----------------------------------
最后的问题:您觉得在socket上传输大文件时,如何能提高传输的效率?
networkstream的同步异步操作是怎么回事?能不能跟我说说他们的区别,最好来一个实例(beginread中的AsyncCallback asyncCallback到底是什么东西)问了好多问题,可是我没有多少分给大家觉得很惭愧(等我有份了一定补给大家),但是我会衷心的谢谢大家
我的mail:[email protected] 如果有code的话您可以mail我
再一次谢谢大家
我的大体思路有两个(参考网上的资料)
----------------------
(1) 个人认为效率比较低
连接..
发送第一个字节块...
等待确认...(接收确认信息)
确认
发送第二个字节块...
等待确认...
确认
发送第三个.....
....
(2)个人认为效率比较高
发送端一直写入网络流
接收端一直读取网络流
----------------------
我在每个字节块的前面加入了一个int型的变量,它表示每次发送文件数据的长度
我根据思路(2)写了代码
如下
----------------------
接收端
[code]
private void Listener() //开始监听传输请求
{
IPHostEntry ipHostInfo =Dns.Resolve(System.Net.Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
this._ls =new TcpListener (ipAddress,6688);
this._ls .Start ();
while(true)
{
Socket socket=this._ls .AcceptSocket ();
this.txtConnect .Text =socket.RemoteEndPoint .ToString ();
Receive(socket); //调用接受文件函数
}
}
//我在每个字节块的前面加入了一个int型的变量,它表示每次发送文件数据的长度
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);
if (datanum > 0) //如果传输的文件字节数>0 证明还有数据没有传输完
{
fs.Write(this._receiveBuf, 4, datanum);
fs.Flush();
}
else //datanum = 0 ,文件发送完毕
{
isRead = false;
}
}
this.txtFile.Text = "文件传输成功";
fs.Close();
}[/code]
----------------------
发送端
[code]
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); //将count加入数组首部
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //写入网络流
sendCount += count;
}
countbuffer = BitConverter.GetBytes(0); //发送文件完后,读出字节数为0
this._ns.Write(countbuffer, 0, countbuffer.Length);
_ns.Close();
fs.Close();
}
}
[/code]
----------------------
我发现有时能够成功,有时却陷入死循环,比如我传输2k的txt,结果很长时间都没有停止,我中断后发现生成了200M的txt
实在搞不懂是为什么,请大家帮我分析分析.
-------------------------------
关于思路(1)我不会控制socket和相对应的networkstream
比如说发送端发送数据后,要等待接收端的确认信息
怎样让发送端停止发送数据来等待确认信息
接收到后又怎样重新发送数据
说简单一点就是发送端和接收端有序的操作网络流的问题
请大家多多指点
-----------------------------------
最后的问题:您觉得在socket上传输大文件时,如何能提高传输的效率?
networkstream的同步异步操作是怎么回事?能不能跟我说说他们的区别,最好来一个实例(beginread中的AsyncCallback asyncCallback到底是什么东西)问了好多问题,可是我没有多少分给大家觉得很惭愧(等我有份了一定补给大家),但是我会衷心的谢谢大家
我的mail:[email protected] 如果有code的话您可以mail我
再一次谢谢大家
补充:
---------------------
接收端
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;
}
非阻塞模型,可以在发送过程中进行读取操作,提高了效率。
当然,在第二次发送前,必须等待第一次发送操作完成才行,需要检测和控制!
{
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 之前,必须使用 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 方法。下面的代码示例异步接收来自远程主机的无连接数据报。IPHostEntry lipa = Dns.Resolve("host.contoso.com");
IPEndPoint lep = new IPEndPoint(lipa.AddressList[0], 11000); Socket s = new Socket(lep.Address.AddressFamily,
SocketType.Dgram,
ProtocolType.Udp);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint tempRemoteEP = (EndPoint)sender;
s.Connect(sender);
try{
while(true){
allDone.Reset();
StateObject so2 = new StateObject();
so2.workSocket = s;
Console.WriteLine("Attempting to Receive data from host.contoso.com");
s.BeginReceiveFrom(so2.buffer, 0, StateObject.BUFFER_SIZE,0, ref tempRemoteEP,
new AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback), so2);
allDone.WaitOne();
}
}
catch (Exception e){
Console.WriteLine(e.ToString());
}
下面的示例使用主机名 www.contoso.com 在端口 11000 上建立 UdpClient 连接。将很短的字符串消息发送到两个单独的远程主机。Receive 方法在接收消息前阻止执行。使用传递给 Receive 的 IPEndPoint 可以显示响应主机的标识。// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(11000);
try{
udpClient.Connect("www.contoso.com", 11000); // Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");
udpClient.Send(sendBytes, sendBytes.Length); // Sends a message to a different host using optional hostname and port parameters.
UdpClient udpClientB = new UdpClient();
udpClientB.Send(sendBytes, sendBytes.Length, "AlternateHostMachineName", 11000); //IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); // Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString()); udpClient.Close();
udpClientB.Close();
}
catch (Exception e ) {
Console.WriteLine(e.ToString());
}
TcpClient 类提供了一些简单的方法,用于在同步阻止模式下通过网络来连接、发送和接收流数据。为使 TcpClient 连接并交换数据,使用 TCP ProtocolType 创建的 TcpListener 或 Socket 必须侦听是否有传入的连接请求。可以使用下面两种方法之一连接到该侦听器: 创建一个 TcpClient,并调用三个可用的 Connect 方法之一。使用远程主机的主机名和端口号创建 TcpClient。此构造函数将自动尝试一个连接。注意
如果要在同步阻止模式下发送无连接数据报,请使用 UdpClient 类。
给继承者的说明 要发送和接收数据,请使用 GetStream 方法来获取一个 NetworkStream。调用 NetworkStream 的 Write 和 Read 方法与远程主机之间发送和接收数据。使用 Close 方法释放与 TcpClient 关联的所有资源。下面的代码示例建立 TcpClient 连接。static void Connect(String server, String message)
{
try
{
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
Int32 port = 13000;
TcpClient client = new TcpClient(server, port);
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message); // Get a client stream for reading and writing.
// Stream stream = client.GetStream();
NetworkStream stream = client.GetStream(); // Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length); Console.WriteLine("Sent: {0}", message); // Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[256]; // String to store the response ASCII representation.
String responseData = String.Empty; // Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData); // Close everything.
stream.Close();
client.Close();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.WriteLine("\n Press Enter to continue...");
Console.Read();
}
关于您说的“首先把文件的总长度和每次发送的大小先发送出去,等接收端接受并分析,然后开始。 ”
client发送文件总长度和每次发送大小,这我会。
可是每次client在发送完一次的数据后,如何设置client等待server的回传信息,client接收到回传信息后,还能继续发送数据呢??
比如
----------------------------------
发送端
while (sendCount < fs.Length && _ns.CanWrite)
{
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //读出要发送的数据 _sendBuf长度1000
countbuffer = BitConverter.GetBytes(count);
countbuffer.CopyTo(clientbuffer,0);
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //写入网络流
sendCount += count;
等待回复信息
接受到回复信息后判断服务器端是否接受成功
如果成功继续循环 (请大家帮我实现)
}
-------------------------------------------
接收端
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);
接受datanum字节数
发送至发送端
等待第2次接受 (请大家帮我实现)
}
else //如果接受字节数为0 就退出
{
isRead = false;
}
}
this.txtFile.Text = "文件传输成功";
fs.Close();
}
可是又碰见一个问题
我的接收端最终要将文件写入数据库的 现在有两个写入方案
--------------------
(1)发送端以单独socket发送数据,接收端单独线程接受数据,
连接..
发送第一个字节块...
等待确认...(接收确认信息)
确认
发送第二个字节块...
等待确认...
确认
发送第三个.....
总体来说是:接受一块数据写入一块数据(已实现分块写入数据库)
但这样我觉得效率不够高
--------------------
(2)发送端多个线程发送数据,接收端多个socket同时接受数据,但这样在写入数据库的时候就出现了数据块顺序问题(不能保证接受数据块顺序的正确性,因为多个socket同时接受)
就算解决了数据块顺序问题,但是有没有可能在(2)的机制下实现多个发送端同时向接收端发送文件
请大家多多指教
--------------------
下面是我自己写的接受端的code,在写入网络流后直接读取在接收端发送的返回信息,什么都不用设置,实现了接收端和发送端轮流操作网络流.接下来我要处理的就是效率问题(多线程发送)
C# code
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;
int servernum = this._ns.Read(_sendBuf,0,4); //在写入网络流后直接读取在接收端发送的返回信息 原
int servercount = BitConverter.ToInt32(_sendBuf, 0); //来它本来就在阻塞,等待着接收端发来的信息,我以为
if (count != servercount) //要人为的阻塞
{
MessageBox.Show("Error");
break;
}
}
countbuffer = BitConverter.GetBytes(0);
this._ns.Write(countbuffer, 0, countbuffer.Length);
_ns.Close();
fs.Close();
}
您能不能给我找个例子,或是写一些关于这个的code
我对socket的异步传输一窍不通,能不能麻烦您找一找这方面的资料
我自己也会去找找,找到了会发到帖子上的对于 zhoufoxcn
msdn上的资料我也看了,对于一点不是很懂s.BeginReceiveFrom(so2.buffer, 0, StateObject.BUFFER_SIZE,0, ref tempRemoteEP,
new AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback), so2);
allDone.WaitOne();为什么要new一个AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback)?AsyncCallback是什么?
Async_Send_Receive.ReceiveFrom_Callback 这个是方法么?
谁能给我讲一讲s.BeginReceiveFrom 执行的步骤和执行顺序对于 jiangsheng
一开始就用socket了,没有找ftp的相关资料
您能不能说说使用ftp的优势?对于 yagebu1983
您说的定义协议
发送文件的时候封装协议!!
接受文件的时候解释协议!!
我没有听说过
您能不能找到这方面的资料给我对于 virusplayer
您说的一直打开是什么意思?
“要有一个通信协议,比如说传输大小,开始,结束,都要定义的”
我不是很懂 能不能详细说说
我写的接收端和发送端 有时候运行正确 有时接受端的文件会少很多数据(甚至发送两次就停止了)接收端 /// <summary>
/// 将每次要发送文件的字节数放置在数据的首部
/// 服务器接收后将接收到的字节数发回
/// 发送端发送完成后接受服务器的发来的字节数
/// 然后与自己发送的字节数比较,进行检验
/// 发送文件完成后发送count=0的消息到服务器
/// 通知服务器停止接受
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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[_sendBuf.Length + 4]; //生成每次发送的buf 首部4个字节表示发送字节数
while (sendCount < fs.Length && _ns.CanWrite)
{
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //从文件中读出数据
countbuffer = BitConverter.GetBytes(count); //得到字节数的buf
countbuffer.CopyTo(clientbuffer,0); //将count放入最终buf
_sendBuf.CopyTo(clientbuffer, 4); //将数据放入最终buf
this._ns.Write(clientbuffer, 0, 4 + count); //发送最终buf
sendCount += count; //更新发送总字节数
int servernum = this._ns.Read(countbuffer,0,4); //等待接收端发来信息
int servercount = BitConverter.ToInt32(countbuffer, 0);//将发送信息转换成count
if (count != servercount)
{
MessageBox.Show("Error in transmit");
break;
}
}
countbuffer = BitConverter.GetBytes(0);
this._ns.Write(countbuffer, 0, countbuffer.Length);
_ns.Close();
fs.Close();
}
/// 从网络流读出数据,读出发送端发送的字节数
/// 根据字节数写入文件并判断是否发送完成
/// 并将字节数写入网络流,让发送端判断是否发送成功
/// 最后停止循环
/// </summary>
/// <param name="socket">c与s之间的socket</param>
private void Receive(Socket socket)
{
NetworkStream ns = new NetworkStream(socket);
FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
bool isRead = true;
byte[] countbuf = new byte[4];
while (isRead)
{
int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length); //从网络流读取数据
int datanum = 0;
datanum = BitConverter.ToInt32(this._receiveBuf, 0); //将字节数转换成int
if (datanum > 0)
{
countbuf = BitConverter.GetBytes(datanum);
ns.Write(countbuf, 0, 4); //将字节数写入网络流
fs.Write(this._receiveBuf, 4, datanum); //写入文件
}
else
{
isRead = false;
}
}
this.txtFile.Text = "文件传输成功";
fs.Close();
}
我的想法是isread为true,直到接受到的数据字节数为0(datanum=0)时,isread才为false(停止循环)
估计问题出在下面
(1)发送端发送完成后就直接read网络流this._ns.Write(clientbuffer, 0, 4 + count); //发送最终buf
sendCount += count; //更新发送总字节数
servernum = this._ns.Read(countbuffer,0,4); //等待接收端发来信息(2)接收端接受到数据后将字节数发回客户端 int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length); //从网络流读取数据
int datanum = 0;
datanum = BitConverter.ToInt32(this._receiveBuf, 0); //将字节数转换成int
if (datanum > 0)
{
countbuf = BitConverter.GetBytes(datanum);
ns.Write(countbuf, 0, 4); //将字节数写入网络流
fs.Write(this._receiveBuf, 4, datanum); //写入文件
请各位大大帮我看看呀
可能是数据传得太快,还没有写到文件中下次数据又来了,导致数据丢失
感谢大家的帮助
剩下就是多线程和socket的异步处理了
谁能帮我找找这方面的资料修改接收端代码/// <summary>
/// 从网络流读出数据,读出发送端发送的字节数
/// 根据字节数写入文件并判断是否发送完成
/// 并将字节数写入网络流,让发送端判断是否发送成功
/// 最后停止循环
/// </summary>
/// <param name="socket">c与s之间的socket</param>
private void Receive(Socket socket)
{
NetworkStream ns = new NetworkStream(socket);
FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
bool isRead = true;
byte[] countbuf = new byte[4];
while (isRead)
{
int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length); //从网络流读取数据
int datanum = 0;
datanum = BitConverter.ToInt32(this._receiveBuf, 0); //将字节数转换成int
if (datanum > 0)
{
fs.Write(this._receiveBuf, 4, datanum); //写入文件
countbuf = BitConverter.GetBytes(datanum);
ns.Write(countbuf, 0, 4); //将字节数写入网络流
}
else
{
isRead = false;
}
}
this.txtFile.Text = "文件传输成功";
fs.Close();
}
3579表示该数据块的编号。 100表示一共分了100个包,后便的数字表示当前是第几个包。
接受方把接到的数据包都保存下来,一旦发现数据不连续,就请求一下。比如3579/100/23 之后得到 3579/100/25
那么就再请求一下 3579/100/24, 发送方得到这个后,再把24包补发一次(包里要注明补发,以免接收方吧计数器弄错),
数据传输完成。接收方返回一个确认指令。传输完成。
那么你在发送前就该先吧数据分段。比如不分段需要1000个包,那么你可以线分成20段,每段50个包。每完成一段,就确认一下,吧数据写入磁盘,继续处理下一段。
不过如果要求传输的是命令队列(一般这东西要求及时处理,不能耽搁)那么你最好采用类似ATM的传输方式。接受一个,处理一个。
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //从文件中读出数据
很疑惑啊,楼主每次都是从文件流的开始位置读起数据,这样测试结果也对??似乎要用sendCount加以控制吧,请指教!