在通过套接字向服务器发送文件数据时,我得到了一些垃圾值?为什么
I am getting some garbage value while sending file data through socket to server? Why?
我正在通过C++中的套接字建立客户端-服务器连接。我成功地连接了它们,但在发送文件大小和文件数据时,我在服务器中也收到了一些垃圾值。
我首先从客户端通过发送系统调用发送文件大小,然后将文件缓冲区发送到服务器。
我在服务器上有recv系统调用,它成功地接收了Filesize,但在获取一些字节后的文件数据时,我得到了垃圾。
客户代码
File = fopen("index.jpg", "rb");
if (!File)
{
MessageBox(L"Error while readaing the file");
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
char* Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%lu", Size);
send(Socket, cSize, MAX_PATH, 0); // File size
send(Socket, Buffer, Size, 0); // File Binary
服务器代码
unsigned long Size;
char *Filesize = new char[1024];
if (recv(Sub, Filesize, 1024, 0)) // File size
{
Size = strtoul(Filesize, NULL, 0); //getting filesize
}
Buffer = new char[Size];
int reader = recv(Sub, Buffer, Size, 0);
Buffer[Size] = ' ';
if (reader == -1) // File Binary
{
MessageBox(L"Perror Recv");
}
else if (reader == 0)
{
MessageBox(L"Connection is Closed");
}
else
{
FILE *File;
File = fopen("test.jpg", "wb");
fwrite((const char*)Buffer, 1, Size, File);
MessageBox(L"DATA Received");
fclose(File);
}
一个问题是您没有正确处理recv()
的返回值。例如:
if (recv(Sub, Filesize, 1024, 0)) // File size
当上面引用的函数返回时,它已经向Filesize
写入了一些字节数(大于0,小于1025)。有多少您的程序不知道,因为您没有将返回值存储到变量中以查找(相反,您只是检查它是否为非零,然后丢弃该值)。因此,Filesize
很可能不仅包含文件大小值,还包含文件数据的某些部分。。。这就是为什么你的文件的那部分数据以后不会在你的程序中写入磁盘的原因。
这里有一个类似的问题:
int reader = recv(Sub, Buffer, Size, 0);
您可以检查reader
,看看它是-1
还是0
(这很好),但在最后一种情况下,当Buffer
包含reader
字节而不是Size
字节时,您只从阵列中取出Size
字节中的fwrite()
(并且reader
可以具有1
和Size
之间的任何值,这取决于TCP堆栈决定在特定的recv()
调用中传递给您的字节数。
还有一个问题是,您发送的MAX_PATH
字节是文件大小,但收到的却是(最多)1024字节的文件大小。MAX_PATH
等于1024吗?如果没有,那么即使recv()
确实填充了所有1024个字节,您的发送方和接收方仍然会彼此不同步,因为多余的字节会出现在未来的recv()
调用中,或者(或者)您会从随后的send()
调用中获得字节,并将其放入FileSize缓冲区。
所以这就是直接的问题——我认为根本的问题是,你对TCP网络的工作方式做出了一些不正确的假设。特别是:
不能保证
send()
和recv()
调用之间的一一对应。(TCP是一种字节流协议,不进行任何数据成帧)您不能依赖于通过对
recv()
的单个调用传递对send()
的单个调用中的N字节数据。send()
的字节将按顺序传递,但无法保证需要多少次对recv()
的调用才能全部接收,也无法保证任何对recv()
的给定调用将写入接收缓冲区的字节数。你不能依赖
recv()
来填满你传递给它的整个缓冲区。recv()
会写尽可能少或尽可能多的字节,无论每次recv()
调用有多少字节,都取决于你的代码来正确处理它。
在实践中,这意味着您需要在循环中调用recv()
,并仔细跟踪每次recv()
调用的返回值,这样您就可以始终准确地知道到目前为止收到了多少字节,从而知道下一个recv()
调用应该在缓冲区内的何处开始写入。
您没有处理send和recv函数的响应,请确保收集这些响应,因为发送和接收的字节数很多,并且需要进一步使用它们。
- 为什么套接字中的 recv() 函数不返回任何内容?
- 为什么我在蓝牙连接()上收到"java.io.IOException:读取失败,套接字可能关闭或超时,读取re
- 为什么 sys 套接字 recv 函数不填充数据但返回字节长度?
- 关于C++套接字,为什么服务器总是返回相同的结果?
- 为什么信号连接会使套接字客户端对象失效?
- 为什么在此 UDP 客户端/服务器示例中没有必要绑定客户端套接字?
- 为什么在使用 select() 时连接到带有第二个套接字的服务器"break"第一次连接?
- 在 ZeroMQ 中绑定订阅者套接字并连接发布者套接字会在代码运行时给出错误.为什么
- 为什么收到的缓冲区大小大于最初通过套接字发送的大小
- 为什么 Windows udp 接收套接字上的超时总是比 SO_RCVTIMEO 设置的长 500 毫秒
- 为什么非阻塞套接字在 connect() 或 accept() 之前是可写的?
- 在通过套接字向服务器发送文件数据时,我得到了一些垃圾值?为什么
- 为什么我应该在关闭套接字之前使用shutdown()
- 为什么Go套接字比C++套接字慢
- 为什么从套接字读取时 CAN 总线帧 ID 向后?
- 当我尝试将UDP套接字绑定到带有SFML的端口时,为什么会遇到错误
- 为什么套接字(AF_INET、SOCK_DGRAM、IPPROTO_UDP)会失败
- 为什么套接字在gdb下失败
- 为什么套接字未正确处理此缓冲区大小
- 为什么套接字在多线程时不工作