【发布时间】:2020-06-25 19:11:59
【问题描述】:
我有一个简单的 TCP/UDP 套接字代码,它所做的只是发送一个以微秒为单位的时间戳,然后接收端在数据包到达时获取一个时间戳并显示它们之间的微秒差异。
在某些计算机上,diff 大部分时间为 0,偶尔会出现尖峰,而在我测试过的其他计算机上,diff 会逐渐变大,并且读取端跟不上发送端。
我也用 Python 对此进行了测试,并发现了相同的行为。我已经测试了所有可能的套接字类型和标志。这感觉像是系统配置问题。我已经在 Windows 7/8/10 和 Server 2012 R2 上进行了测试。这种行为在每个人(大公司,大量计算机测试)上都会发生,也不会发生。
我也尝试了一些注册表优化,但似乎没有任何帮助,因为这个问题也发生在 TCP 和 UDP 中。例如,我将附上我的 C++ 代码,您可以在您的计算机上运行它,看看会发生什么,这两个选项中的任何一个都有可能。
发件人:
#pragma comment(lib, "Ws2_32.lib")
#include "winsock2.h"
#include <iostream>
#include <string>
#include <chrono>
#include "Mstcpip.h"
#include "WS2tcpip.h"
#define BUFFSIZE 16
const char* getSocketErrorDescription(int socketError)
{
static char msg[100];
sprintf(msg, "Winsock error code");
return msg;
}
int write_select(UINT_PTR filedes, long microsSec)
{
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(filedes, &set);
timeout.tv_sec = 0;
timeout.tv_usec = microsSec;
/* select returns 0 if timeout, 1 if input available, -1 if error. */
return select(FD_SETSIZE, NULL, &set, NULL, &timeout);
}
int main()
{
int counter = 0;
WORD version = MAKEWORD(2, 2);
WSADATA data;
WSAStartup(version, &data);
sockaddr_in localAddr;
ZeroMemory(&localAddr, sizeof(localAddr));
localAddr.sin_family = PF_INET;
localAddr.sin_port = htons((u_short)5555);
//localAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
InetPton(PF_INET, "127.0.0.1", &(localAddr.sin_addr));
SOCKET sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == INVALID_SOCKET)
{
std::cout << "SocketClient::create socket failed" << std::endl;
}
if (connect(sockfd, (sockaddr*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR)
{
std::cout << ("connect failed. %s", getSocketErrorDescription(WSAGetLastError())) << std::endl;
}
std::cout << "Sending..." << std::endl;
while (true)
{
counter++;
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration);
__int64 s_t = microseconds.count();
std::string strMsg = std::to_string(s_t);
while (write_select(sockfd, 10000) == 0)
{
std::cout << ("%s: timeout", strMsg.c_str()) << std::endl;
}
if (send(sockfd, strMsg.c_str(), BUFFSIZE, 0) == SOCKET_ERROR)
{
int socketError = WSAGetLastError();
std::cout << ("failed to send string. %s", getSocketErrorDescription(socketError)) << std::endl;;
}
Sleep(2);
std::cout << "Counter: " << counter << std::endl;
}
}
接收者:
#pragma comment(lib, "Ws2_32.lib")
#include "winsock2.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <chrono>
#include "Mstcpip.h"
#include "WS2tcpip.h"
#define BUFFSIZE 16
const char* getSocketErrorDescription(int socketError)
{
static char msg[100];
sprintf(msg, "Winsock error code");
return msg;
}
int read_select(UINT_PTR filedes, long microsSec)
{
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(filedes, &set);
timeout.tv_sec = 0;
timeout.tv_usec = microsSec;
/* select returns 0 if timeout, 1 if input available, -1 if error. */
return select(FD_SETSIZE, &set, NULL, NULL, &timeout);
}
void parseMsg(std::string& buffer, std::vector<std::string>* messages_list)
{
while (buffer.size() >= 16)
{
messages_list->push_back(buffer.substr(0, 16));
buffer.erase(0, 16);
}
}
int main()
{
int counter = 0;
//std::ofstream res_file;
//res_file.open("D:\\cpp_times.txt");
WORD version = MAKEWORD(2, 2);
WSADATA data;
WSAStartup(version, &data);
sockaddr_in localAddr;
ZeroMemory(&localAddr, sizeof(localAddr));
localAddr.sin_family = PF_INET;
localAddr.sin_port = htons((u_short)5555);
//localAddr.sin_addr.s_addr = INADDR_ANY;
InetPton(PF_INET, "127.0.0.1", &(localAddr.sin_addr));
SOCKET sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == INVALID_SOCKET)
{
std::cout << "SocketClient::create socket failed" << std::endl;
}
if(bind(sockfd, (sockaddr*)&localAddr, sizeof(localAddr)) != 0)
{
int socketError = WSAGetLastError();
std::cout << ("bind failed %s", getSocketErrorDescription(socketError)) << std::endl;
}
if (listen(sockfd, SOMAXCONN) == SOCKET_ERROR)
{
std::cout << ("listen failed") << std::endl;
}
int clilen = sizeof(localAddr);
SOCKET new_socket = accept(sockfd, (sockaddr*)&localAddr, &clilen);
if (new_socket < 0)
std::cout << "ERROR on accept" << std::endl;
std::cout << "Listening..." << std::endl;
while (true)
{
int nbytesRead = 0;
std::string m_buffer;
char recvbuf[BUFFSIZE];
// Receive until the peer closes the connection
// if (read_select(new_socket, 10000))
// {
// nbytesRead = recv(new_socket, recvbuf, BUFFSIZE, 0);
//
// }
// else
// {
// //std::cout << ("%s: timeout", strMsg.c_str()) << std::endl;
// continue;
// }
nbytesRead = recv(new_socket, recvbuf, BUFFSIZE, 0);
if (nbytesRead > 0)
{
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration);
__int64 r_t = microseconds.count();
std::string strMsg = std::to_string(r_t);
m_buffer.append(recvbuf, nbytesRead);
std::vector<std::string> message_list;
parseMsg(m_buffer, &message_list);
for (auto msg : message_list)
{
counter++;
__int64 diff = r_t - _atoi64(msg.c_str());
std::cout << "SendTime: " << msg.c_str() << " ReceiveTime: " << r_t << " Diff: " << diff << std::endl;
std::cout << "Counter: " << counter << std::endl;
//res_file << diff << std::endl;
}
}
else
{
continue;
}
}
}
【问题讨论】:
-
您正在尝试通过 TCP 发送消息。 TCP 不是消息协议,因此您必须自己实现一个并将其置于 TCP 之上。
标签: c++ c sockets network-programming