我有一个用于文件发送的客户端和服务器代码。出于某种原因,我需要在客户端接收并从服务器发送...
一切都很完美,在某些情况下,所有文件都可以完美地发送和接收。在另一种情况下发送几个文件后程序崩溃。不明白问题在哪里......
错误:
客户端
// client code
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Client003
{
const string destFilePath = @"..\..\..\";
const int BufferSize = 1024;
public static void StartReceiving()
{
// Data buffer for sending data.
byte[] buffer;
// FileStream to read data
FileStream fileStream;
int fileNameLen = 0;
string fileName = "";
long fileLen = 0;
int NoOfPackets = 0;
int receivedBytes = 0;
int i, j;
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket receiver = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
receiver.Connect(remoteEP);
buffer = new byte[4];
receiver.Receive(buffer, 4, 0);
int filesNumber = BitConverter.ToInt32(buffer, 0);
for (i = 0; i < filesNumber; i++)
{
buffer = new byte[4];
receiver.Receive(buffer, 4, 0);
fileNameLen = BitConverter.ToInt32(buffer, 0);
// --
buffer = new byte[fileNameLen];
receiver.Receive(buffer, fileNameLen, 0);
fileName = Encoding.UTF8.GetString(buffer);
// --
buffer = new byte[8];
receiver.Receive(buffer, 8, 0);
fileLen = BitConverter.ToInt64(buffer, 0);
// --
NoOfPackets = Convert.ToInt32(Math.Ceiling(
Convert.ToDouble(fileLen) / Convert.ToDouble(BufferSize) ));
fileStream = new FileStream(destFilePath + fileName, FileMode.OpenOrCreate, FileAccess.Write);
receivedBytes = 0;
// --
for (j = 0; j < NoOfPackets; j++)
{
if (fileLen > BufferSize)
{
buffer = new byte[BufferSize];
receivedBytes = receiver.Receive(buffer, BufferSize, 0);
fileStream.Write(buffer, 0, receivedBytes);
fileLen -= BufferSize;
}
else
{
buffer = new byte[fileLen];
receivedBytes = receiver.Receive(buffer, (int)fileLen, 0);
fileStream.Write(buffer, 0, receivedBytes);
}
}
fileStream.Close();
}
// Release the socket.
receiver.Shutdown(SocketShutdown.Both);
receiver.Close();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartReceiving();
return 0;
}
}
服务器
//server code
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
class Server003
{
public static void StartListening()
{
// Data buffer for incoming data.
byte[] buffer;
byte[] fileNameByte;
byte[] fileNameLenByte;
byte[] fileLenByte;
// FileStream to write data
FileStream fileStream;
Int64 fileLen = 0;
int NoOfPackets = 0;
int readBytes = 0;
int i;
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
Console.WriteLine("Waiting for a connection...");
// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
Int32 filesNumber = binFilesNames.Count;
byte[] filesNumberByte = BitConverter.GetBytes(filesNumber);
handler.Send(filesNumberByte);
// --
foreach (string binName in binFilesNames)
{
fileNameByte = Encoding.UTF8.GetBytes(binName);
fileNameLenByte = BitConverter.GetBytes(fileNameByte.Length);
handler.Send(fileNameLenByte);
handler.Send(fileNameByte);
// --
fileStream = new FileStream(sourceFilePath + binName, FileMode.Open, FileAccess.Read);
fileLen = fileStream.Length;
fileLenByte = BitConverter.GetBytes(fileLen);
handler.Send(fileLenByte);
// --
NoOfPackets = Convert.ToInt32(Math.Ceiling(
Convert.ToDouble(fileLen) / Convert.ToDouble(BufferSize)));
for (i = 0; i < NoOfPackets; i++)
{
if (fileLen > BufferSize)
{
buffer = new byte[BufferSize];
// reeding data from file and writing it to the bytes "buffer"
readBytes = fileStream.Read(buffer, 0, BufferSize);
// send bytes from "buffer"
handler.Send(buffer, readBytes, SocketFlags.None);
fileLen -= BufferSize;
}
else
{
buffer = new byte[fileLen];
// reeding data from file and writing it to the bytes "buffer"
readBytes = fileStream.Read(buffer, 0, (int)fileLen);
// send bytes from "buffer"
handler.Send(buffer, readBytes, SocketFlags.None);
}
}
fileStream.Close();
}
// Release the socket.
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static List<string> GetFiles()
{
var dir = new DirectoryInfo(sourceFilePath); // folder with files
var files = new List<string>(); // List with file names
foreach (FileInfo file in dir.GetFiles("T*260000.bin"))
{
files.Add(Path.GetFileName(file.FullName));
}
return files;
}
public static int Main(String[] args)
{
binFilesNames = GetFiles();
StartListening();
return 0;
}
const string sourceFilePath = @"..\..\..\Binaries\";
static List<string> binFilesNames;
const int BufferSize = 1024;
}
UPD: 我考虑了指向LB2的时刻。这是接收部分,它可以根据需要运行:
while ((receivedBytes = receiver.Receive(buffer)) > 0) // receive bytes to "buffer"
{
var tmpBuff = buffer.Take(receivedBytes); // takes first receivedBytes elements
bufferList.AddRange(tmpBuff);
}
但我不明白如何发送工作。当我立刻发送整个数据时 - 一切正常,但当我尝试部分发送时崩溃:
此作品和整个数据已发送:
handler.Send(buffer);
这一次崩溃:
int sentBytes = 0;
int sumSentBytes = 0;
do
{
// send bytes from "buffer"
sentBytes = handler.Send(buffer, sumSentBytes, BufferSize, SocketFlags.None);
sumSentBytes += sentBytes;
}
while (sentBytes > 0);
那么构建大量数据的最佳方法是什么(在我的情况下约为20Mb,但这取决于它)?
答案 0 :(得分:1)
代码中存在多个错误,能够明确指出此特定来源的位置。以下是您应该注意的一些事项以及代码需要清理的地方:
Socket
类为IDisposable
,因此应包含在using
中。 (我不知道这是完整的程序,还是只是一个带有驱动程序main()的代码段,但是如果你打电话StartReceiving
足够多次,它就会泄漏内存。)FileStream
(您在for
循环中有一个)是IDisposable
,因此应该包含在using
中。 (调用.Close()
实际上可能已经足够清理,但仍然可以更好地使用using
。) Socket.Receive()
的使用不正确。您不能假设您收到了所请求的字节数。如果连接丢失,Receive()
将返回0
,或者接收缓冲区中当前可用的字节数(最多请求的计数)。所以当你经历:
buffer = new byte[fileNameLen];
receiver.Receive(buffer, fileNameLen, 0);
fileName = Encoding.UTF8.GetString(buffer);
// --
buffer = new byte[8];
receiver.Receive(buffer, 8, 0);
fileLen = BitConverter.ToInt64(buffer, 0);
...你很可能只读取部分fileName字节,得到部分fileName,然后文件名的余数字节实际上(错误地)被解释为fileLen。
您正确使用receivedBytes
将收到的字节复制到文件流,但是您错误地将fileLen
递减了BufferSize
而不是receivedBytes
,从而破坏了您的文件通过可能只编写部分流,在代码的这一部分:
receivedBytes = receiver.Receive(buffer, BufferSize, 0);
fileStream.Write(buffer, 0, receivedBytes);
fileLen -= BufferSize;
您继续为每次调用byte[]
的循环重新分配新的.Receive
,这是不必要的。您可以继续重复使用相同的缓冲区。
?
消息(可能是编码问题)。请陷阱并发布实际消息。这些只是我通过随意审查发现的一些事情。其中一些是罪魁祸首,还是存在其他一些问题,很难确定存在这些问题。
答案 1 :(得分:1)
我猜你得到exception:
ArgumentOutOfRangeException:size大于缓冲区的长度减去offset参数的值。
您必须从size
参数中减去已发送的字节数:
int bytesToSend = BufferSize - sumSentBytes;
sentBytes = handler.Send(buffer, sumSentBytes, bytesToSend, SocketFlags.None);