我正在尝试通过TCP套接字从向量发送数据。
我正在使用向量填充0至4999的向量,然后将其发送到套接字。
客户端,我将数据接收到一个向量中,然后将其数据复制到另一个向量中,直到从服务器接收到所有数据为止。
我面临的问题是,当我接收到数据时,有时会得到所有数据,有时我只会接收到0到1625之间的正确数据,然后我会得到垃圾数据直到结束(请参见下图) )。例如,我什至收到了从0到2600的正确数据,然后从2601到3500收到了垃圾数据,最后从3501到4999再次得到了正确数据。
(左列是行号,右列是数据)。
这是服务器端:
vector<double> values2;
for(int i=0; i<5000; i++)
values2.push_back(i);
skt.sendmsg(&values2[0], values2.size()*sizeof(double));
sendmsg函数:
void Socket::sendmsg(const void *buf, size_t len){
int bytes=-1;
bytes = send(m_csock, buf, len, MSG_CONFIRM);
cout << "Bytes sent: " << bytes << endl;
}
客户端 :
vector<double> final;
vector<double> msgrcvd(4096);
do{
bytes += recv(sock, &msgrcvd[0], msgrcvd.size()*sizeof(double), 0);
cout << "Bytes received: " << bytes << endl;
//Get rid of the trailing zeros
while(!msgrcvd.empty() && msgrcvd[msgrcvd.size() - 1] == 0){
msgrcvd.pop_back();
}
//Insert buffer content into final vector
final.insert(final.end(), msgrcvd.begin(), msgrcvd.end());
}while(bytes < sizeof(double)*5000);
//Write the received data in a txt file
for(int i=0; i<final.size(); i++)
myfile << final[i] << endl;
myfile.close();
字节的输出正确,服务器在发送数据时输出40 000,客户端在接收数据时也输出40 000。
删除结尾的零,然后将缓冲区的内容插入到新的向量中不是很有效,但是我认为这不是问题。如果您对如何提高效率有任何线索,那就太好了!
我真的不知道问题出在何时发送数据或何时接收数据,我也不清楚为什么有时(很少)获得所有数据。
最佳答案
recv
接收字节,不必等待所有已发送的数据。因此,您可以接收双打的一部分。
如果您收到完整的double
值,则代码将起作用,但是当您收到部分值时,代码将失败。您应该在char
缓冲区中接收数据,然后将其解压缩为双精度。 (如果服务器和客户端不同,则可能转换字节顺序。)
#include <cstring> // For memcpy
std::array<char, 1024> msgbuf;
double d;
char data[sizeof(double)];
int carryover = 0;
do {
int b = recv(sock, &msgbuf[carryover], msgbuf.size() * sizeof(msgbuf[0]) - carryover, 0);
bytes += b;
b += carryover;
const char *mp = &msgbuf[0];
while (b >= sizeof(double)) {
char *bp = data;
for (int i = 0; i < sizeof(double); ++i) {
*bp++ = *mp++;
}
std::memcpy(&d, data, sizeof(double));
final.push_back(d);
b -= sizeof(double);
}
carryover = b % sizeof(double);
// Take care of the extra bytes. Copy them down to the start of the buffer
for (int j = 0; j < carryover; ++j) {
msgbuf[j] = *mp++;
}
} while (bytes < sizeof(double) * 5000);
这使用从What's a proper way of type-punning a float to an int and vice-versa?的punning类型将接收的二进制数据转换为double,并假定客户端和服务器的字节序相同。
顺便说一句,接收者如何知道它正在接收多少个值?服务器代码中混合了硬编码值(
5000
)和动态值(.size()
)。注意:代码未经编译或测试