Last active
June 7, 2020 12:55
-
-
Save Romain-P/b9dd9e9e880b49294504ab18d0398576 to your computer and use it in GitHub Desktop.
non-blocking sockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <winsock2.h> | |
#include <ws2tcpip.h> | |
#include <windows.h> | |
#include <vector> | |
#include <string> | |
#include <iostream> | |
namespace AsyncSocket { | |
inline std::vector<WSAPOLLFD> watchList; | |
enum PollCallMethod { BON_BLOCKING = 0, BLOCKING = -1 }; | |
/** | |
* Non-blocking function | |
* Detects whenever sockets passed as arguments are ready to read some incoming data. | |
* | |
* If read events are detected, the callback handler is fired with the concerned socket | |
* | |
* @return [[ | |
* 0: no event detected | |
* -1: error | |
* >1: events detected, next read won't be blocking | |
* ]] | |
*/ | |
inline int socketPollEvents(void (*readEventHandler)(unsigned int socket)) { | |
int result = WSAPoll(&watchList[0], watchList.size(), PollCallMethod::BON_BLOCKING); | |
if (result > 0) | |
for (auto &it: watchList) | |
if ((it.revents & POLLRDNORM) || (it.revents & POLLRDBAND)) /* on read event */ | |
readEventHandler(it.fd); | |
return result; | |
} | |
/** | |
* Initializes a socket with a given ip and port | |
* @returns [[ | |
* -1: error | |
* +1: socket descriptor (unsigned int) | |
* ]] | |
*/ | |
inline unsigned int socketConnect(char const *ip, int port) { | |
SOCKET descriptor; | |
SOCKADDR_IN hints = {0}; | |
hints.sin_addr.s_addr = inet_addr(ip); | |
hints.sin_family = AF_INET; | |
hints.sin_port = htons(port); | |
descriptor = descriptor(AF_INET, SOCK_STREAM, 0); | |
bind(descriptor, (SOCKADDR *) &hints, sizeof(hints)); | |
if (connect(descriptor, (SOCKADDR *) &hints, sizeof(hints)) == SOCKET_ERROR) | |
return -1; | |
/* add the socket to watch list for read operations */ | |
watchList.push_back((WSAPOLLFD) { | |
.fd = descriptor, | |
.events = POLLIN /* specify we only want to watch read operations */ | |
}); | |
return descriptor; | |
} | |
/** | |
* @param descriptor a socket ready to read on | |
* @param handler lua handler in order to process the data | |
* | |
* Handler params | |
* @param data received data | |
* @param bytes -1 on error, 0 if socket closed, > 0 for the number of bytes in the buffer | |
*/ | |
inline void socketRead(unsigned int descriptor, void (*handler)(char const data[], unsigned int bytes)) { | |
char buffer[1024]; | |
unsigned int bytes = recv((SOCKET) descriptor, buffer, sizeof(buffer), 0); | |
buffer[bytes] = 0; | |
handler(buffer, bytes); | |
} | |
/** | |
* | |
* @param descriptor Socket to write on | |
* @param data Data to send | |
* @param length Length of the buffer | |
*/ | |
inline void socketWrite(unsigned int descriptor, char const *data, int length) { | |
send((SOCKET) descriptor, data, length, 0); | |
} | |
/** | |
* @param descriptor socket to close | |
*/ | |
inline void socketClose(unsigned int descriptor) { | |
/* remove socket from watchlist */ | |
watchList.erase(std::remove_if(watchList.begin(), watchList.end(), [descriptor](WSAPOLLFD &pollFd) { | |
return pollFd.fd == descriptor; | |
}), watchList.end()); | |
closesocket((SOCKET) descriptor); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local socketHandlers = {} //table mapping [socket] to [readHandler] | |
local socketFrame = CreateFrame("socketFrame", nil, UIParent) | |
socketFrame:SetScript("OnEvent", | |
function() | |
SocketPollEvents( | |
function(socket) | |
SocketRead(socket, socketHandlers[socket]) | |
end | |
) | |
end | |
) | |
function CreateSocket(ip, port, readHandler) | |
local socket = SocketConnect(ip, port) | |
socketHandlers[socket] = readHandler | |
return socket | |
end | |
--------------------------------------------------------------------- | |
-- Usage example | |
local socket = CreateSocket("127.0.0.1", 123, | |
function(data) | |
print("data received: " .. data) | |
end | |
) | |
-- later | |
CloseSocket(socket) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment