You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

uoSocketClientServerASyncCommunicationTest.cpp 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*********************************************************************
  2. * Software License Agreement (AGPL-3 License)
  3. *
  4. * OpenViBE SDK Test Software
  5. * Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
  6. * Copyright (C) Inria, 2015-2017,V1.0
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program.
  19. * If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <string>
  22. #include <cstring>
  23. #include <thread>
  24. #include <condition_variable>
  25. #include <vector>
  26. #include "socket/IConnection.h"
  27. #include "socket/IConnectionClient.h"
  28. #include "socket/IConnectionServer.h"
  29. #include "ovtAssert.h"
  30. namespace {
  31. std::condition_variable gServerStartedCondVar;
  32. std::mutex gServerStartedMutex;
  33. std::vector<std::string> gReceivedData;
  34. bool gServerStarted = false;
  35. // server callback run from a child thread
  36. void onServerListening(const int port, const size_t expectedPacketCount)
  37. {
  38. gReceivedData.clear();
  39. Socket::IConnection* clientConnection = nullptr;
  40. // create server
  41. Socket::IConnectionServer* server = Socket::createConnectionServer();
  42. server->listen(port);
  43. // keep the scope braces here, as it ensures mutex is released
  44. {
  45. std::lock_guard<std::mutex> lockOnServerStart(gServerStartedMutex);
  46. gServerStarted = true;
  47. }
  48. // notify main thread that the server is created so that it can connect a single client
  49. gServerStartedCondVar.notify_one();
  50. // loop until all packet are received
  51. while (gReceivedData.size() < expectedPacketCount)
  52. {
  53. if (server->isReadyToReceive()) { clientConnection = server->accept(); }
  54. if (clientConnection && clientConnection->isReadyToReceive())
  55. {
  56. size_t dataSize = 0;
  57. size_t bytesToReceive = sizeof(dataSize);
  58. size_t bytesReceived = 0;
  59. char dataBuffer[32];
  60. // first receive data size
  61. while (bytesReceived < bytesToReceive) { bytesReceived += clientConnection->receiveBuffer(&dataSize, bytesToReceive - bytesReceived); }
  62. // then receive data
  63. bytesToReceive = dataSize;
  64. bytesReceived = 0;
  65. while (bytesReceived < bytesToReceive) { bytesReceived += clientConnection->receiveBuffer(dataBuffer, bytesToReceive - bytesReceived); }
  66. gReceivedData.push_back(std::string(dataBuffer, dataSize));
  67. }
  68. }
  69. server->release();
  70. }
  71. void sendData(Socket::IConnectionClient* client, void* data, const size_t size)
  72. {
  73. const size_t bytesToSend = size;
  74. size_t bytesSent = 0;
  75. while (bytesSent < bytesToSend) { bytesSent += client->sendBuffer(data, bytesToSend - bytesSent); }
  76. }
  77. } // namespace
  78. int uoSocketClientServerASyncCommunicationTest(int argc, char* argv[])
  79. {
  80. OVT_ASSERT(argc == 4, "Failure to retrieve tests arguments. Expecting: server_name port_number packet_count");
  81. const std::string serverName = argv[1];
  82. int portNumber = std::atoi(argv[2]);
  83. size_t packetCount = size_t(std::atoi(argv[3]));
  84. // test asynchronous data transmission from a single client to server:
  85. // - launch a server on a background thread
  86. // - connect a single client
  87. // - make client sending data
  88. // - marke server receiving and storing data
  89. // - join the thread and do the assertions on received data when no data race is possible
  90. // create client
  91. Socket::IConnectionClient* client = Socket::createConnectionClient();
  92. // launch server on background thread
  93. std::thread serverThread(onServerListening, portNumber, packetCount);
  94. // wait until the server is started to connect clients
  95. std::unique_lock<std::mutex> lock(gServerStartedMutex);
  96. gServerStartedCondVar.wait(lock, []() { return gServerStarted; });
  97. client->connect(serverName.c_str(), portNumber);
  98. // transmit data
  99. // transmission follows the protocol: data size transmission + data transmission
  100. const std::string baseData = "Data packet index: ";
  101. for (size_t sendIndex = 0; sendIndex < packetCount; ++sendIndex)
  102. {
  103. std::string tmp = baseData + std::to_string(sendIndex);
  104. size_t size = tmp.size();
  105. sendData(client, &size, sizeof(size));
  106. sendData(client, const_cast<char*>(tmp.c_str()), size);
  107. }
  108. serverThread.join(); // wait until the end of the thread
  109. // release resources
  110. client->close();
  111. client->release();
  112. // do the assertion on the main thread
  113. OVT_ASSERT(gReceivedData.size() == packetCount, "Failure to retrieve packet count");
  114. for (size_t receivedIndex = 0; receivedIndex < packetCount; ++receivedIndex)
  115. {
  116. OVT_ASSERT_STREQ(gReceivedData[receivedIndex], (baseData + std::to_string(receivedIndex)), "Failure to retrieve packet");
  117. }
  118. return EXIT_SUCCESS;
  119. }