C++ 客户端套接字发送原始文件和文件大小,Java 客户端总是多获得 8 个字节。即使强制限制为 -8 字节文件也不可读
C++ client socket sends original file and file size, Java client always get 8 bytes more. Even after force limiting to -8 bytes file is unreadable
有一段时间,我被这个问题困扰
使用我在此处找到的一段 C++ 代码,在我看来应该可以很好地实际发送准确数量的数据,我猜问题出在 Java 代码或未知的地方。
此外,发送简单的 "Hello World"
数据时,传输正确完成。
如果有人能解决它,或提供宝贵的意见,我将不胜感激。
我是 运行 Windows 10 jdk1.8.0_221 和 Visual Studio 2022.
我知道将来可能需要在 return 中将 filesize
作为字符串和知识标志发送,但为简单起见,C++ 客户端仅发送一个包含已知数据量的文件.
这是Java的一面:
while(!Terminate)
{
byte[] bytes = new byte[1];//code was different for a real buffer
//...still +8 bytes
while (in.available() > 0)
{
in.read(bytes);
out.write(bytes);
out.flush();
}
}
out.close();
- 我试过之后又是 8 个字节:
int filesize = 15670;
int cnt = 0;
while (cnt<filesize)
{
out.write(in.read());
out.flush();
cnt++;
}
这让我觉得保存时添加了 8 个字节。
C++代码:
int SendBuffer(SOCKET s, const char* buffer, int bufferSize, int chunkSize = 4 * 1024) {
int l = -1;
int i = 0;
while (i < bufferSize)
{
int l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0);
//int l = send(s, &buffer[i], bufferSize , MSG_DONTROUTE);
int j = 0;
std::cout << i << std::endl;
while (l < 0) { Beep(433, 1000); j++; std::cout << "shiban l" << l << std::endl; l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0); } // this is an error
i += l;
}
return i;
}
int64_t SendFile(SOCKET s, const std::string fileName, int chunkSize) {
const int64_t fileSize = GetFileSize(fileName);
if (fileSize < 0) { return -1; }
std::ifstream file(fileName, std::ifstream::binary);
if (file.fail()) { return -1; }
if (SendBuffer(s, reinterpret_cast<const char*>(&fileSize),
sizeof(fileSize)) != sizeof(fileSize)) {
return -2;
}
char* buffer = new char[chunkSize];
bool errored = false;
int64_t i = fileSize;
auto bytes_sent = 0;
while (i > 0) {
const int64_t ssize = __min(i, (int64_t)chunkSize);
if (!file.read(buffer, ssize)) { errored = true; break; }
const int l = SendBuffer(s, buffer, (int)ssize);
bytes_sent += l;
int bi = 0;
if (l < 0) { std::cout <<" err :"<< l<<std::endl; errored = true; break; }
i -= l;
}
delete[] buffer;
file.close();
std::cout << "bytes_sent:" << bytes_sent << std::endl;
return errored ? -3 : fileSize;
}
C++ 代码在发送文件数据之前发送文件大小(好),但没有进行足够的错误处理(坏),并且它没有以 platform-agnostic 格式发送文件大小(不好)。
没关系,因为显示的 Java 代码甚至没有在读取文件数据之前尝试读取文件大小(非常糟糕),也没有注意 return in.read()
的值以了解 实际 接收了多少字节。但即使是,C++ 代码也将大小作为 8 字节整数发送(大文件 > 2GB 时需要),但 Java 代码使用 4 字节整数代替(错误)。 C++ 还在 SendFile()
.
中为 bytes_sent
使用 4 字节整数
试试像这样的东西:
BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream dis = new DataInputStream(bis);
long filesize = dis.readLong();
if (filesize > 0)
{
byte[] bytes = new byte[4*1024];
do
{
int chunkSize = (int) Math.min(filesize, (long) bytes.length);
dis.readFully(bytes, 0, chunkSize);
out.write(bytes, 0, chunkSize);
out.flush();
filesize -= chunkSize;
}
while (filesize > 0);
}
out.close();
bool SendBuffer(SOCKET s, const char* buffer, int bufferSize) {
while (bufferSize > 0)
{
int numSent = send(s, buffer, bufferSize, 0/*MSG_DONTROUTE*/);
if (numSent < 0) {
Beep(433, 1000);
return false;
}
}
return true;
}
int64_t SendFile(SOCKET s, const std::string fileName, int chunkSize) {
const int64_t fileSize = GetFileSize(fileName);
if (fileSize < 0) { return -1; }
std::ifstream file(fileName, std::ifstream::binary);
if (file.fail()) { return -1; }
const int64_t tmp = htonll(fileSize); // see
if (!SendBuffer(s, reinterpret_cast<const char*>(&tmp), sizeof(tmp))) {
return -2;
}
std::vector<char> buffer(chunkSize);
bool errored = false;
int64_t bytes_sent = 0;
while (fileSize > 0) {
int ssize = static_cast<int>(std::min<int64_t>(fileSize, chunkSize));
if (!file.read(buffer.data(), ssize)) { errored = true; break; }
if (!SendBuffer(s, buffer.data(), ssize)) { errored = true; break; }
fileSize -= ssize;
}
file.close();
if (errored) {
std::cout << "err" << std::endl;
return -3;
}
std::cout << "bytes_sent:" << bytes_sent << std::endl;
return bytes_sent;
}
有一段时间,我被这个问题困扰
使用我在此处找到的一段 C++ 代码,在我看来应该可以很好地实际发送准确数量的数据,我猜问题出在 Java 代码或未知的地方。
此外,发送简单的 "Hello World"
数据时,传输正确完成。
如果有人能解决它,或提供宝贵的意见,我将不胜感激。 我是 运行 Windows 10 jdk1.8.0_221 和 Visual Studio 2022.
我知道将来可能需要在 return 中将 filesize
作为字符串和知识标志发送,但为简单起见,C++ 客户端仅发送一个包含已知数据量的文件.
这是Java的一面:
while(!Terminate)
{
byte[] bytes = new byte[1];//code was different for a real buffer
//...still +8 bytes
while (in.available() > 0)
{
in.read(bytes);
out.write(bytes);
out.flush();
}
}
out.close();
- 我试过之后又是 8 个字节:
int filesize = 15670;
int cnt = 0;
while (cnt<filesize)
{
out.write(in.read());
out.flush();
cnt++;
}
这让我觉得保存时添加了 8 个字节。
C++代码:
int SendBuffer(SOCKET s, const char* buffer, int bufferSize, int chunkSize = 4 * 1024) {
int l = -1;
int i = 0;
while (i < bufferSize)
{
int l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0);
//int l = send(s, &buffer[i], bufferSize , MSG_DONTROUTE);
int j = 0;
std::cout << i << std::endl;
while (l < 0) { Beep(433, 1000); j++; std::cout << "shiban l" << l << std::endl; l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0); } // this is an error
i += l;
}
return i;
}
int64_t SendFile(SOCKET s, const std::string fileName, int chunkSize) {
const int64_t fileSize = GetFileSize(fileName);
if (fileSize < 0) { return -1; }
std::ifstream file(fileName, std::ifstream::binary);
if (file.fail()) { return -1; }
if (SendBuffer(s, reinterpret_cast<const char*>(&fileSize),
sizeof(fileSize)) != sizeof(fileSize)) {
return -2;
}
char* buffer = new char[chunkSize];
bool errored = false;
int64_t i = fileSize;
auto bytes_sent = 0;
while (i > 0) {
const int64_t ssize = __min(i, (int64_t)chunkSize);
if (!file.read(buffer, ssize)) { errored = true; break; }
const int l = SendBuffer(s, buffer, (int)ssize);
bytes_sent += l;
int bi = 0;
if (l < 0) { std::cout <<" err :"<< l<<std::endl; errored = true; break; }
i -= l;
}
delete[] buffer;
file.close();
std::cout << "bytes_sent:" << bytes_sent << std::endl;
return errored ? -3 : fileSize;
}
C++ 代码在发送文件数据之前发送文件大小(好),但没有进行足够的错误处理(坏),并且它没有以 platform-agnostic 格式发送文件大小(不好)。
没关系,因为显示的 Java 代码甚至没有在读取文件数据之前尝试读取文件大小(非常糟糕),也没有注意 return in.read()
的值以了解 实际 接收了多少字节。但即使是,C++ 代码也将大小作为 8 字节整数发送(大文件 > 2GB 时需要),但 Java 代码使用 4 字节整数代替(错误)。 C++ 还在 SendFile()
.
bytes_sent
使用 4 字节整数
试试像这样的东西:
BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream dis = new DataInputStream(bis);
long filesize = dis.readLong();
if (filesize > 0)
{
byte[] bytes = new byte[4*1024];
do
{
int chunkSize = (int) Math.min(filesize, (long) bytes.length);
dis.readFully(bytes, 0, chunkSize);
out.write(bytes, 0, chunkSize);
out.flush();
filesize -= chunkSize;
}
while (filesize > 0);
}
out.close();
bool SendBuffer(SOCKET s, const char* buffer, int bufferSize) {
while (bufferSize > 0)
{
int numSent = send(s, buffer, bufferSize, 0/*MSG_DONTROUTE*/);
if (numSent < 0) {
Beep(433, 1000);
return false;
}
}
return true;
}
int64_t SendFile(SOCKET s, const std::string fileName, int chunkSize) {
const int64_t fileSize = GetFileSize(fileName);
if (fileSize < 0) { return -1; }
std::ifstream file(fileName, std::ifstream::binary);
if (file.fail()) { return -1; }
const int64_t tmp = htonll(fileSize); // see
if (!SendBuffer(s, reinterpret_cast<const char*>(&tmp), sizeof(tmp))) {
return -2;
}
std::vector<char> buffer(chunkSize);
bool errored = false;
int64_t bytes_sent = 0;
while (fileSize > 0) {
int ssize = static_cast<int>(std::min<int64_t>(fileSize, chunkSize));
if (!file.read(buffer.data(), ssize)) { errored = true; break; }
if (!SendBuffer(s, buffer.data(), ssize)) { errored = true; break; }
fileSize -= ssize;
}
file.close();
if (errored) {
std::cout << "err" << std::endl;
return -3;
}
std::cout << "bytes_sent:" << bytes_sent << std::endl;
return bytes_sent;
}