Ftp文件传输完成后,为什么接收不到完成后server发送的命令信息?

Ack_001 2010-11-26 11:57:03
我在做的一个Ftp文件传输工具,在文件下载过程中发生了奇怪的现象,小弟百思不解,故向各位大哥请教!小弟先谢了!!!
问题如下:
在文件下载过程中,当文件较小时(小于15M)程序正常没有任何异常;但是但文件稍大时,如:30M。这时候文件能够 完成下载,下载后文件大小根ftp服务器上文件大小一样,但是就是接收不到ftp服务器返回的下载成功信息。<调试中发现,程序阻塞在接受ftp命令消息处...>导致程序卡在那里了!

各位大哥,多多指教哈!
主要代码为:

//------------------------------ SocketTcp 类------------------------------//
class SocketTCP
{
public :
SocketTCP();
void SetBlocking(bool Blocking);
Socket::Status Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout = 0.f);
bool Listen(unsigned short Port);
Socket::Status Accept(SocketTCP& Connected, IPAddress* Address = NULL);
Socket::Status Send(const char* Data, std::size_t Size);
Socket::Status Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived);
bool Close(); // 关闭套接字
bool IsValid() const; // 验证套接字是否有效
bool operator ==(const SocketTCP& Other) const;
bool operator !=(const SocketTCP& Other) const;
bool operator <(const SocketTCP& Other) const;
private :
friend class Selector<SocketTCP>;
SocketTCP(SocketHelper::SocketType Descriptor);
void Create(SocketHelper::SocketType Descriptor = 0);
// 成员变量
SocketHelper::SocketType mySocket; ///< Socket descriptor
Uint32 myPendingHeader; ///< Data of the current pending packet header, if any
Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any
bool myIsBlocking; ///< Is the socket blocking or non-blocking ?
};

//---------------------------------Ftp 类--------------------------------------//
class SFML_API Ftp : NonCopyable
{
public :
enum TransferMode
{
Binary, ///< Binary mode (file is transfered as a sequence of bytes)
Ascii, ///< Text mode using ASCII encoding
Ebcdic ///< Text mode using EBCDIC encoding
};
// ---------------------------报文类----------------------------------------//
class Response
{
public :
enum Status
{
// 枚举的报文常量,就没列出来了
};
Response(Status Code = InvalidResponse, const std::string& Message = "");
bool IsOk() const;
Status GetStatus() const;
const std::string& GetMessage() const;

private :
Status myStatus; ///< Status code returned from the server
std::string myMessage; ///< Last message received from the server
};
// 其他成员函数就没列举出来了,不然太长了
Ftp(bool translateMode = false);
~Ftp();
Response Download(const std::string& DistantFile, const std::string& DestPath, TRANSLATEINFO* pTransInfo = NULL, TransferMode Mode = Binary);
Response Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode = Binary);

private:
Response SendCommand(const std::string& Command, const std::string& Parameter = "");
Response GetResponse();
class DataChannel;
friend class DataChannel;
SocketTCP myCommandSocket; ///< Socket holding the control connection with the server>
};

//----------------------------------DataChannel 类----------------------------------//
class Ftp::DataChannel : NonCopyable
{
public :
DataChannel(Ftp& Owner);
~DataChannel();
Ftp::Response Open(Ftp::TransferMode Mode);
void Send(const std::vector<char>& Data);
void Receive(std::vector<char>& Data);
bool RecevieFile(std::string &filename, DWORD filesize, TRANSLATEINFO* pTransInfo = NULL);
private :
Ftp& myFtp; ///< Reference to the owner Ftp instance
SocketTCP myDataSocket; ///< Socket used for data transfers
SocketTCP FtpCommandSocket; ///< Ftp command socket>
CallBackShowSpeed cbShowSpeed; ///回调函数指针变量
};

// 文件下载函数
Ftp::Response Download(const std::string& DistantFile, const std::string& DestPath, TRANSLATEINFO* pTransInfo, TransferMode Mode)
{
// Open a data channel using the given transfer mode
DataChannel Data(*this); // 打开数据通道,接收数据《DataChannel是'数据类'》
Response Resp = Data.Open(Mode); /*Response 是'ftp报文类',记录命令通道返回的命令消息*/
if (Resp.IsOk()) // 命令通道返回的信息表示数据通道连接成功
{
// Get the remote file size
Ftp::FileInfoResponse ResSize = GetFileSize(DistantFile);
std::string remoteStr = ResSize.GetFileInfo();
DWORD dwRometeSize = atol(remoteStr.c_str());
// Tell the server to start the transfer
Resp = SendCommand("RETR", DistantFile);
if (Resp.IsOk())
{
// Extract the filename from the file path
std::string Filename = DistantFile;
std::string::size_type Pos = Filename.find_last_of("/\\");
if (Pos != std::string::npos)
Filename = Filename.substr(Pos + 1);
// Make sure the destination path ends with a slash
std::string Path = DestPath;
if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
Path += "/";
Path += Filename;
if (!Data.RecevieFile(Path, dwRometeSize, pTransInfo))
return Response(Response::InvalidFile); //error
Resp = GetResponse(); /*程序就卡在这一步了*/《获取完成下载后,命令通道返回的信息》
}
}
return Resp;
}
// 从命令通道获取报文方法
Ftp::Response Ftp::GetResponse()
{
for (;;)
{
char Buffer[1024];
std::size_t Length;
// 调试中,发现阻塞在Receive()这里了!!!(myCommandSocket是Ftp类的命令通道套接字类对象)
if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done)
{
return Response(Response::ConnectionClosed);
}

// 消息处理...
}
}
// 命令通道接收文件函数
bool Ftp::DataChannel::RecevieFile(std::string &filename, DWORD filesize, TRANSLATEINFO* pTransInfo)
{
// Receive data
char Buffer[1024] = {0};
std::size_t Received = 0;
DWORD size = filesize;
float receivedSpeed = 0.0f;
// Create file in local computer
std::ofstream localfile(filename.c_str(), std::ios_base::binary);
if (!localfile)
return false;
while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done)
{
size -= Received;
localfile.write(Buffer, static_cast<int>(Received));
localfile.flush();
memset(Buffer, 0, sizeof(Buffer));
receivedSpeed = 100*((filesize-size)/static_cast<double>(filesize));
cbShowSpeed(filename, receivedSpeed, pTransInfo);
}
// Closed the localfile
localfile.close();
myDataSocket.Close();
return true;
}
// 套接字接收数据函数
Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived)
{
// First clear the size received
SizeReceived = 0;
// Check that socket is valid
if (!IsValid())
return Socket::Error;
// Check parameters
if (Data && MaxSize)
{
// Receive a chunk of bytes
int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
// Check the number of bytes received
if (Received > 0)
{
SizeReceived = static_cast<std::size_t>(Received);
return Socket::Done;
}
else if (Received == 0)
{
return Socket::Disconnected;
}
else
{
return SocketHelper::GetErrorStatus();
}
}
else
{
// Error...
std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
return Socket::Error;
}
}
...全文
270 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
Ack_001 2010-11-26
  • 打赏
  • 举报
回复
第一次发帖,发现格式太乱了。看来要注意了,不过小弟,新手,望各位大哥海涵了
Ack_001 2010-11-26
  • 打赏
  • 举报
回复
决定修改代码格式,重传!

//------------------------------ SocketTcp 类------------------------------//
class SocketTCP
{
public :
SocketTCP();
void SetBlocking(bool Blocking);
Socket::Status Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout = 0.f);
bool Listen(unsigned short Port);
Socket::Status Accept(SocketTCP& Connected, IPAddress* Address = NULL);
Socket::Status Send(const char* Data, std::size_t Size);
Socket::Status Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived);
bool Close(); // 关闭套接字
bool IsValid() const; // 验证套接字是否有效
bool operator ==(const SocketTCP& Other) const;
bool operator !=(const SocketTCP& Other) const;
bool operator <(const SocketTCP& Other) const;
private :
friend class Selector<SocketTCP>;
SocketTCP(SocketHelper::SocketType Descriptor);
void Create(SocketHelper::SocketType Descriptor = 0);
// 成员变量
SocketHelper::SocketType mySocket; ///< Socket descriptor
Uint32 myPendingHeader; ///< Data of the current pending packet header, if any
Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any
bool myIsBlocking; ///< Is the socket blocking or non-blocking ?
};

//---------------------------------Ftp 类--------------------------------------//
class SFML_API Ftp : NonCopyable
{
public :
enum TransferMode
{
Binary, ///< Binary mode (file is transfered as a sequence of bytes)
Ascii, ///< Text mode using ASCII encoding
Ebcdic ///< Text mode using EBCDIC encoding
};
// ---------------------------报文类----------------------------------------//
class Response
{
public :
enum Status
{
// 枚举的报文常量,就没列出来了
};
Response(Status Code = InvalidResponse, const std::string& Message = "");
bool IsOk() const;
Status GetStatus() const;
const std::string& GetMessage() const;
private :
Status myStatus; ///< Status code returned from the server
std::string myMessage; ///< Last message received from the server
};
// 其他成员函数就没列举出来了,不然太长了
Ftp(bool translateMode = false);
~Ftp();
Response Download(const std::string& DistantFile, const std::string& DestPath,
TRANSLATEINFO* pTransInfo = NULL, TransferMode Mode = Binary);
Response Upload(const std::string& LocalFile, const std::string& DestPath,
TransferMode Mode = Binary);
private:
Response SendCommand(const std::string& Command, const std::string& Parameter = "");
Response GetResponse();
class DataChannel;
friend class DataChannel;
SocketTCP myCommandSocket; ///< Socket holding the control connection with the server>
};

//----------------------------------DataChannel 类----------------------------------//
class Ftp::DataChannel : NonCopyable
{
public :
DataChannel(Ftp& Owner);
~DataChannel();
Ftp::Response Open(Ftp::TransferMode Mode);
void Send(const std::vector<char>& Data);
void Receive(std::vector<char>& Data);
bool RecevieFile(std::string &filename, DWORD filesize, TRANSLATEINFO* pTransInfo = NULL);
private :
Ftp& myFtp; ///< Reference to the owner Ftp instance
SocketTCP myDataSocket; ///< Socket used for data transfers
SocketTCP FtpCommandSocket; ///< Ftp command socket>
CallBackShowSpeed cbShowSpeed; ///回调函数指针变量
};

// 文件下载函数
Ftp::Response Download(const std::string& DistantFile, const std::string& DestPath, TRANSLATEINFO* pTransInfo, TransferMode Mode)
{
// Open a data channel using the given transfer mode
DataChannel Data(*this); // 打开数据通道,接收数据《DataChannel是'数据类'》
Response Resp = Data.Open(Mode); /*Response 是'ftp报文类',记录命令通道返回的命令消息*/
if (Resp.IsOk()) // 命令通道返回的信息表示数据通道连接成功
{
// Get the remote file size
Ftp::FileInfoResponse ResSize = GetFileSize(DistantFile);
std::string remoteStr = ResSize.GetFileInfo();
DWORD dwRometeSize = atol(remoteStr.c_str());
// Tell the server to start the transfer
Resp = SendCommand("RETR", DistantFile);
if (Resp.IsOk())
{
// Extract the filename from the file path
std::string Filename = DistantFile;
std::string::size_type Pos = Filename.find_last_of("/\\");
if (Pos != std::string::npos)
Filename = Filename.substr(Pos + 1);
// Make sure the destination path ends with a slash
std::string Path = DestPath;
if (!Path.empty() && (Path[Path.size() - 1] != '\\')
&& (Path[Path.size() - 1] != '/'))
{
Path += "/";
}
Path += Filename;
if (!Data.RecevieFile(Path, dwRometeSize, pTransInfo))
return Response(Response::InvalidFile); //error
Resp = GetResponse(); /*程序就卡在这一步了*/《获取完成下载后,命令通道返回的信息》
}
}
return Resp;
}
// 从命令通道获取报文方法
Ftp::Response Ftp::GetResponse()
{
for (;;)
{
char Buffer[1024];
std::size_t Length;
// 调试中,发现阻塞在Receive()这里了!!!(myCommandSocket是Ftp类的命令通道套接字类对象)
if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done)
{
return Response(Response::ConnectionClosed);
}

// 消息处理...
}
}
// 命令通道接收文件函数
bool Ftp::DataChannel::RecevieFile(std::string &filename, DWORD filesize, TRANSLATEINFO* pTransInfo)
{
// Receive data
char Buffer[1024] = {0};
std::size_t Received = 0;
DWORD size = filesize;
float receivedSpeed = 0.0f;
// Create file in local computer
std::ofstream localfile(filename.c_str(), std::ios_base::binary);
if (!localfile)
return false;
while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done)
{
size -= Received;
localfile.write(Buffer, static_cast<int>(Received));
localfile.flush();
memset(Buffer, 0, sizeof(Buffer));
receivedSpeed = 100*((filesize-size)/static_cast<double>(filesize));
cbShowSpeed(filename, receivedSpeed, pTransInfo);
}
// Closed the localfile
localfile.close();
myDataSocket.Close();
return true;
}
// 套接字接收数据函数
Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived)
{
// First clear the size received
SizeReceived = 0;
// Check that socket is valid
if (!IsValid())
return Socket::Error;
// Check parameters
if (Data && MaxSize)
{
// Receive a chunk of bytes
int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
// Check the number of bytes received
if (Received > 0)
{
SizeReceived = static_cast<std::size_t>(Received);
return Socket::Done;
}
else if (Received == 0)
{
return Socket::Disconnected;
}
else
{
return SocketHelper::GetErrorStatus();
}
}
else
{
// Error...
std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
return Socket::Error;
}
}

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧