Merge pull request #206 from NPrincen/develop

Minimize Send and Receive Socket Timeout Delays
This commit is contained in:
Jason Watkins
2020-05-16 15:15:12 -07:00
committed by GitHub
3 changed files with 58 additions and 40 deletions

View File

@@ -117,13 +117,16 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port)
exit(EXIT_FAILURE);
}
// Set timeout to 100ms
// Set socket timeout period for sendUDP to 1 millisecond
// Without this, playback may become choppy due to process blocking
#ifdef _WIN32
DWORD timeout = 100;
// Minimum socket timeout in Windows is 1 millisecond (0 makes it blocking)
DWORD timeout = 1;
#else
// Set socket timeout to 1 millisecond = 1,000 microseconds to make it the same as Windows (0 makes it blocking)
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 250000;
timeout.tv_usec = 1000;
#endif
if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
{
@@ -188,13 +191,13 @@ int sendUDP(XPCSocket sock, char buffer[], int len)
/// \returns If an error occurs, a negative number. Otherwise, the number of bytes read.
int readUDP(XPCSocket sock, char buffer[], int len)
{
#ifdef _WIN32
// Windows readUDP needs the select command- minimum timeout is 1ms.
// Without this playback becomes choppy
// For readUDP, use the select command - minimum timeout of 0 makes it polling.
// Without this, playback may become choppy due to process blocking
// Definitions
FD_SET stReadFDS;
FD_SET stExceptFDS;
fd_set stReadFDS;
fd_set stExceptFDS;
struct timeval timeout;
// Setup for Select
FD_ZERO(&stReadFDS);
@@ -202,12 +205,13 @@ int readUDP(XPCSocket sock, char buffer[], int len)
FD_ZERO(&stExceptFDS);
FD_SET(sock.sock, &stExceptFDS);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000;
// Set timeout period for select to 0.05 sec = 50 milliseconds = 50,000 microseconds (0 makes it polling)
// TO DO - This could be set to 0 if a message handling system were implemented, like in the plugin.
timeout.tv_sec = 0;
timeout.tv_usec = 50000;
// Select Command
int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv);
int status = select(sock.sock+1, &stReadFDS, NULL, &stExceptFDS, &timeout);
if (status < 0)
{
printError("readUDP", "Select command error");
@@ -218,11 +222,9 @@ int readUDP(XPCSocket sock, char buffer[], int len)
// No data
return 0;
}
// If no error: Read Data
status = recv(sock.sock, buffer, len, 0);
#else
// For apple or linux-just read - will timeout in 0.5 ms
int status = (int)recv(sock.sock, buffer, len, 0);
#endif
if (status < 0)
{
printError("readUDP", "Error reading socket");

View File

@@ -56,22 +56,25 @@ namespace XPC
return;
}
// Set Timout
int usTimeOut = 500;
// Set timeout period for SendTo to 1 millisecond
// Without this, playback may become choppy due to process blocking
#ifdef _WIN32
DWORD msTimeOutWin = 1; // Minimum socket timeout in Windows is 1ms
if(setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&msTimeOutWin, sizeof(msTimeOutWin)) != 0)
// Minimum socket timeout in Windows is 1 millisecond (0 makes it blocking)
DWORD timeout = 1;
#else
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
#endif
if (setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
Log::FormatLine(LOG_ERROR, tag, "ERROR: Failed to set timeout. (Error code %i)", err);
}
#else
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = usTimeOut;
setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
Log::WriteLine(LOG_ERROR, tag, "ERROR: Failed to set timeout.");
#endif
}
}
UDPSocket::~UDPSocket()
@@ -87,43 +90,54 @@ namespace XPC
int UDPSocket::Read(unsigned char* dst, int maxLen, sockaddr* recvAddr) const
{
socklen_t recvaddrlen = sizeof(*recvAddr);
int status = 0;
#ifdef _WIN32
// Windows readUDP needs the select command- minimum timeout is 1ms.
// Without this playback becomes choppy
// For Read, use the select command - minimum timeout of 0 makes it polling.
// Without this, playback may become choppy due to process blocking
// Definitions
FD_SET stReadFDS;
FD_SET stExceptFDS;
timeval tv;
fd_set stReadFDS;
fd_set stExceptFDS;
struct timeval timeout;
// Setup for Select
FD_ZERO(&stReadFDS);
FD_SET(sock, &stReadFDS);
FD_ZERO(&stExceptFDS);
FD_SET(sock, &stExceptFDS);
tv.tv_sec = 0;
tv.tv_usec = 250;
// Set timeout period for select to 0 to poll the socket
timeout.tv_sec = 0;
timeout.tv_usec = 0;
// Select Command
int result = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv);
if (result == SOCKET_ERROR)
int status = select(sock+1, &stReadFDS, NULL, &stExceptFDS, &timeout);
if (status < 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
Log::FormatLine(LOG_ERROR, tag, "ERROR: Select failed. (Error code %i)", err);
#else
Log::WriteLine(LOG_ERROR, tag, "ERROR: Select failed.");
#endif
return -1;
}
if (result <= 0) // No Data or error
if (status == 0)
{
// No data
return -1;
}
// If no error: Read Data
status = recvfrom(sock, (char*)dst, maxLen, 0, recvAddr, &recvaddrlen);
if (status < 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
Log::FormatLine(LOG_ERROR, tag, "ERROR: Receive failed. (Error code %i)", err);
#else
// For apple or linux-just read - will timeout in 0.5 ms
status = (int)recvfrom(sock, dst, 5000, 0, recvAddr, &recvaddrlen);
Log::WriteLine(LOG_ERROR, tag, "ERROR: Receive failed.");
#endif
}
return status;
}

View File

@@ -13,6 +13,8 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif