有几天我一直试图将整个PNG读成一个字符串,所以我可以通过winsock2将它上传到服务器,它似乎在几个字符或某种断行后停止读取文件,是否有任何特殊原因和解决方法。
我尝试了很多解决方案,这现在开始让我疯狂。我正在使用的当前代码如下
std::ifstream in ("some.png", ios::in|ios::binary|ios::ate );
std::string contents;
if (in)
{
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
in.close();
length = contents.size();
}
我不知道问题可能是什么,因为我对c ++相对较新,我已经通过google拖了几天而没有可行的解决方案。
请帮忙
更新代码发布到服务器
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return;
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0)
throw;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_port = htons(80);
LPHOSTENT host = gethostbyname("127.0.0.1");
if (!host)
throw;
service.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
if (connect(fd, (SOCKADDR *)&service, sizeof(service)) < 0)
throw;
int length ;
std::ifstream in (CCFileUtils::fullPathFromRelativePath("back.png"), ios::in|ios::binary|ios::ate );
std::string contents;
if (in){
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
in.close();
length = contents.size();
}else
std::string str =
"POST /index.php HTTP/1.1\r\n"
"Host: metapps.co.uk\r\n"
"Accept: */*\r\n";
char buffer1 [50];
str.append( "Content-Length: 121\r\n" );
str.append( "\r\n" );
str.append( "Content-Disposition: form-data; name=\"tmp\";filename=\"photo.png\"\r\n" );
str.append( "Content-Type: image/dds\r\n" );
sprintf (buffer1, "Content-Length: %d\r\n", length);
str.append( buffer1 );
str.append( contents );
str.append( "\r\n\x01A\r\n" );
// send str ...
send(fd, str.c_str() , strlen( str.c_str() ) +1 , 0);
char ret[1024];
recv(fd,ret,strlen(ret),0);
closesocket(fd);
WSACleanup();
}
更新2
它与Null终结符字符串和追加方法
有关如果我这样做
str.append( "he\0llo" );
服务器只会显示“他”
如果我这样做
str.append( "hello" );
我得到你好,希望这个信息可以带来解决方案
答案 0 :(得分:3)
send(fd, str.c_str() , strlen( str.c_str() ) +1 , 0);
char ret[1024];
strlen( str.c_str() ) +1
将告诉您输出中第一个0字节的位置,而不是字符串的长度。最好通过str.size()
来获取字符串的长度。
此外,正如WhosCraig mentioned一样,您正在调用strlen(ret)
,其中ret
未初始化。相反,使用
std::array<char, 1024> ret;
recv(fd,ret,ret.size(),0);
或者可能更具活力的东西。
答案 1 :(得分:1)
单向 [1] :
std::ifstream in("some.png", ios::binary);
std::vector<unsigned char> contents(std::istreambuf_iterator<char>(in), {});
另一个
std::ostringstream oss;
oss << in.rdbuf();
std::string contents = iss.str();
正如其他人所指出的那样,通常没有必要在内存中同时拥有全部内容。它导致可伸缩性问题。如果可能的话,尽量避免使用它。
[1] 如果您的编译器受到标准挑战,请将其分解:
std::istreambuf_iterator<char> f(in), l;
std::vector<unsigned char> contents(f, l);
答案 2 :(得分:0)
您正在使用&contents[0]
来获取字符串使用的内部缓冲区的地址。据我所知,在你调用.c_str()之前,不保证这个缓冲区是偶然的,甚至是正确的大小,所以你只是无法传递地址。
对原始二进制数据使用std::vector<char>
或std::array<char, n>
。它们总是保证有顺序缓冲区。
哦,顺便说一句,没有必要将整个文件读入一个大缓冲区。只需逐段阅读即可。
答案 3 :(得分:0)
我解决了!
我发送的标题内容长度是固定长度121
str.append( "Content-Length: 121\r\n" );
因此服务器因此将消息体截断为这个长度,我不知道服务器如此认真地使用了这个值,如果它太大也会抛出500错误。
为邮件正文发送正确的长度修复它。
我还将标题与邮件正文分开并使用了
std::vector<char>
根据@youdontneedtothankme存储邮件正文
感谢所有的回复和评论,帮助我在经历了长达一周的挫折之后找到问题的根源,我的生活现在可以继续了哈哈:)
Stackoverflow FTW!