我正在尝试构建一个在本地主机上运行的快速服务器和客户端。这个想法是从另一个程序发送数据 block ,并快速处理它。一次只有一个客户端连接到服务器。
我首先尝试使用 boost::asio 库实现它。一切正常,除了吞吐量非常慢,415 兆字节/秒。
然后我开始用 winsock 创建一个测试用例,它也有非常相似的吞吐量,434 兆字节/秒。非常慢。
我原本期望在 40 GB 或每秒至少几 GB 的范围内有更多数据。
我很感激任何建议,因为我不擅长网络编程。
我当前的客户端功能:
bool sendDataWin(size_t size, const size_t blocksize, size_t port)
{
int result;
struct addrinfo *addressinfo = nullptr, hints;
auto sport = std::to_string(port);
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the local address and port to be used by the server
result = getaddrinfo("localhost", sport.c_str(), &hints, &addressinfo);
if (result != 0) {
printf("Error at client socket(): %ld\n", WSAGetLastError());
return false;
}
SOCKET connection = socket(
addressinfo->ai_family,
addressinfo->ai_socktype,
addressinfo->ai_protocol);
if (connection == INVALID_SOCKET) {
printf("Error at client socket(): %ld\n", WSAGetLastError());
freeaddrinfo(addressinfo);
return false;
}
// Try to put loopback fast path on.
bool value;
DWORD dwBytesRet;
int status =
WSAIoctl(
connection,
SIO_LOOPBACK_FAST_PATH,
&value,
sizeof(bool),
NULL,
0,
&dwBytesRet,
0,
0);
if (status == SOCKET_ERROR) {
DWORD LastError = ::GetLastError();
if (LastError == WSAEOPNOTSUPP) {
printf("client call is not supported :: SIO_LOOPBACK_FAST_PATH\n");
}
}
// Connect to server.
result = connect(connection, addressinfo->ai_addr, (int)addressinfo->ai_addrlen);
if (result == SOCKET_ERROR) {
printf("Error at client socket(): %ld\n", WSAGetLastError());
closesocket(connection);
return false;
}
freeaddrinfo(addressinfo);
std::vector<uint8_t> buffer;
buffer.resize(blocksize);
size_t total = 0;
do {
size_t sendSize = blocksize;
size_t next = total + sendSize;
if (next > size)
{
sendSize -= next - size;
}
// Echo the buffer back to the sender
result = send(connection, (const char*)buffer.data(), (int)sendSize, 0);
if (result == SOCKET_ERROR) {
printf("client send failed: %d\n", WSAGetLastError());
closesocket(connection);
return false;
}
total += sendSize;
} while (total < size);
result = shutdown(connection, SD_SEND);
if (result == SOCKET_ERROR) {
printf("client shutdown failed: %d\n", WSAGetLastError());
closesocket(connection);
return false;
}
// cleanup
closesocket(connection);
return true;
}
服务器函数:
bool serverReceiveDataWin(size_t size, const size_t blocksize, size_t port)
{
int result;
struct addrinfo *addressinfo = nullptr, *ptr = nullptr, hints;
auto sport = std::to_string(port);
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the local address and port to be used by the server
result = getaddrinfo(nullptr, sport.c_str(), &hints, &addressinfo);
if (result != 0) {
printf("Error at server socket(): %ld\n", WSAGetLastError());
return false;
}
SOCKET ListenSocket = socket(addressinfo->ai_family, addressinfo->ai_socktype, addressinfo->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("Error at server socket(): %ld\n", WSAGetLastError());
freeaddrinfo(addressinfo);
return false;
}
// Try to put loopback fast path on.
bool value;
DWORD dwBytesRet;
int status =
WSAIoctl(
ListenSocket,
SIO_LOOPBACK_FAST_PATH,
&value,
sizeof(bool),
NULL,
0,
&dwBytesRet,
0,
0);
if (status == SOCKET_ERROR) {
DWORD LastError = ::GetLastError();
if (LastError == WSAEOPNOTSUPP) {
printf("server call is not supported :: SIO_LOOPBACK_FAST_PATH\n");
}
}
// Setup the TCP listening socket
result = bind(ListenSocket, addressinfo->ai_addr, (int)addressinfo->ai_addrlen);
if (result == SOCKET_ERROR) {
printf("server bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(addressinfo);
closesocket(ListenSocket);
return false;
}
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
printf("Listen failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
return false;
}
// Accept a client socket
SOCKET ClientSocket = accept(ListenSocket, nullptr, nullptr);
if (ClientSocket == INVALID_SOCKET) {
printf("server accept failed: %d\n", WSAGetLastError());
closesocket(ListenSocket);
return false;
}
std::vector<uint8_t> buffer;
buffer.resize(blocksize);
size_t total = 0;
// Receive until the peer shuts down the connection
do {
size_t currentSize = blocksize;
size_t next = total + currentSize;
if (next > size)
{
currentSize -= next - size;
}
result = recv(ClientSocket, (char*)buffer.data(), (int)currentSize, 0);
if (result > 0)
{
total += result;
}
else if (result == 0)
{
printf("server Connection closing...\n");
return false;
}
else {
printf("server recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return false;
}
} while (total < size);
result = shutdown(ClientSocket, SD_SEND);
if (result == SOCKET_ERROR) {
printf("server shutdown failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return false;
}
// cleanup
closesocket(ClientSocket);
return true;
}
测试程序本身是:
int main()
{
int width = 1920;
int height = 1080;
const size_t totalBpp = 3;
const size_t totalSize = width * height * totalBpp;
size_t port = 27140;
size_t times = 1000;
size_t expectedData = totalSize * times;
// Initialize Winsock
int iResult;
WSADATA wsaData;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
std::cout << "WSAStartup failed: " << iResult << std::endl;
return EXIT_FAILURE;
}
std::atomic_bool serverOk{ false };
std::atomic_bool clientOk{ false };
auto start = std::chrono::high_resolution_clock::now();
std::thread server = std::thread([&] {
serverOk = serverReceiveDataWin(expectedData, totalSize, port);
});
std::thread client = std::thread([&] {
clientOk = sendDataWin(expectedData, totalSize, port);
});
client.join();
server.join();
auto end = std::chrono::high_resolution_clock::now();
WSACleanup();
if (!(clientOk && serverOk))
{
if (!serverOk) std::cout << "Server was not OK." << std::endl;
if (!clientOk) std::cout << "Client was not OK." << std::endl;
return EXIT_FAILURE;
}
std::chrono::duration<double> diff = end - start;
double frameTime = diff.count() / times;
double fps = 1.0 / frameTime;
std::cout << "Sent: " << width << "x" << height << "_" << totalBpp << "(" << totalSize << "). times: " << times << std::endl;
std::cout << "frameTime: " << frameTime << "s." << std::endl;
std::cout << "fps: " << fps << "." << std::endl;
std::cout << "transfer rate : " << ((expectedData / diff.count()) / 1048576) << " mebibytes/s." << std::endl;
std::cout << "transfer rate : " << ((expectedData / diff.count()) / 1000000) << " megabytes/s." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds{ 60 });
return EXIT_SUCCESS;
}
在我的机器上我得到了这些结果:
Sent: 1920x1080_3(6220800).times : 1000
frameTime : 0.0138217s.
fps : 72.35.
transfer rate : 429.225 mebibytes / s.
transfer rate : 450.075 megabytes / s.
似乎是我的防火墙/杀毒软件的问题,我首先卸载了 F-secure,速度增加到 500 兆字节/秒。卸载并重新启动后,速度增加到 4000 兆字节/秒。
最佳答案
几点。
IOCTL 调用不正确。
bool value;
DWORD dwBytesRet;
int status =
WSAIoctl(
ListenSocket,
SIO_LOOPBACK_FAST_PATH,
&value,
sizeof(bool),
NULL,
0,
&dwBytesRet,
0,
0);
这应该传递一个设置为 1 的 DWORD(32 位整数)。上面的代码传递一个从未初始化为任何东西的 C++ bool 值(可能只有 1 个字节)。
关于C++ 低吞吐量 winsock TCP 测试应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52000333/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server