我正在编写一个文件传输客户端/服务器应用程序其中客户端在windows7上操作,并使用vb.net编写服务器运行在linux mint上,用c++编写(我使用的是vmware)我的问题是,当我试图将文件(如图像)上传到服务器时,接收到的数据丢失了许多字节,这些字节也表示控制字符(如EOT、ETB…),我猜它们被读取为tcp控制字符,并被接收操作系统忽略。我已经用简单的文本文件(大小高达4MB)测试了这个应用程序,没有任何问题。有没有办法防止系统忽略这些字节?
这是接收文件的c++函数:
string readSockBytes(int port,int num,int size)
{
int dcmbuffSize = 1460;
int n;
stringstream temp;
string strBuffer,Sbuffer;
char Rbuffer[dcmbuffSize];
struct socketVar sockets;
sockets = setSocket(port);
sockets = sockListen(sockets);
cout<<"user connectedn";
strBuffer = readsock(sockets);
cout<<strBuffer.substr(0,strBuffer.find("$"))<<endl;
if(num == atoi(strBuffer.substr(0,strBuffer.find("$")).c_str()))
Sbuffer = "ready$";
else
{
Sbuffer = "exit$";
close(sockets.newsockfd);
close(sockets.sockfd);
}
n = writesock(sockets, Sbuffer, 100);
if (n < 0) error("ERROR writing to socket");
while(strBuffer.length() < fileSize)
{
n = read(sockets.newsockfd,Rbuffer,dcmbuffSize-1);
if (n < 0) error("ERROR reading from socket");
temp.str(Rbuffer);
strBuffer = strBuffer+temp.str();
}
strBuffer = strBuffer.substr(0,size);
return strBuffer;
}
问题很可能是您发送了二进制数据。二进制数据可以包含零。零是正常的字符串终止符。
这意味着当您执行temp.str(Rbuffer)
(假设temp
是std::stringstream
)时,它只从Rbuffer
获取数据,直到第一个零。
不使用例如std::stringstream
,而是使用std::string
:
while(strBuffer.length() < fileSize)
{
char buffer[2048];
ssize_t n = read(sockets.newsockfd, buffer, sizeof(buffer));
if (n <= 0)
{
// An error, or connection closed
if (n < 0)
error("ERROR reading from socket");
break;
}
// Create a string of `n` bytes, including possible string terminators
// and add it to out current buffer
strBuffer += std::string(buffer, n);
}
这里需要记住的重要一点是,不能将接收到的数据用作字符串!如果它是二进制数据,那么它肯定会包含字符串终止符,因此您必须将其视为二进制数据,而不是字符串(即使您可以将其存储在std::string
中)。
您还需要注意,您不能打印数据,因为许多二进制值要么无法打印,要么将打印为"垃圾"。
最后,如果您读取和写入二进制文件,则需要以二进制模式打开它们,否则会出现字节0x0d
和0x0a
的错误(即回车和换行)。