Skip to content

Instantly share code, notes, and snippets.

@GurixD
Last active June 23, 2022 20:32
Show Gist options
  • Save GurixD/becb340fcee09ce2fec24718373688eb to your computer and use it in GitHub Desktop.
Save GurixD/becb340fcee09ce2fec24718373688eb to your computer and use it in GitHub Desktop.
#include <cstring>
#include <iostream>
#include <string>
#ifdef __linux__
#define PLATFORM_LINUX
#elif defined _WIN32
#define PLATFORM_WINDOWS
#else
#define PLATFORM_UNKNOWN
#endif
#ifdef PLATFORM_WINDOWS
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#elif defined PLATFORM_LINUX
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <stddef.h>
#include <poll.h>
using SOCKET = int;
#define closesocket(fd) ::close(fd)
#endif
const int PORT = 23232;
int main()
{
#ifdef PLATFORM_WINDOWS
WSAData wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
#endif
addrinfo* addresses;
addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
//hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
getaddrinfo("localhost", std::to_string(PORT).c_str(), &hints, &addresses);
SOCKET fd = socket(addresses->ai_family, addresses->ai_socktype, addresses->ai_protocol);
int ret = connect(fd, addresses->ai_addr, static_cast<int>(addresses->ai_addrlen));
freeaddrinfo(addresses);
std::string in = "Hello client";
ret = send(fd, in.c_str(), in.size() + 1, 0);
char buffer[1024];
ret = recv(fd, buffer, sizeof(buffer), 0);
std::cout << "Recvd: " << buffer << std::endl;
while (in != "exit")
{
std::cin >> in;
ret = send(fd, in.c_str(), in.size() + 1, 0);
}
closesocket(fd);
#ifdef PLATFORM_WINDOWS
WSACleanup();
#endif
return 0;
}
#include <cstring>
#include <iostream>
#include <string>
#ifdef __linux__
#define PLATFORM_LINUX
#elif defined _WIN32
#define PLATFORM_WINDOWS
#else
#define PLATFORM_UNKNOWN
#endif
#ifdef PLATFORM_WINDOWS
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#elif defined PLATFORM_LINUX
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <stddef.h>
#include <poll.h>
using SOCKET = int;
#define closesocket(fd) ::close(fd)
#endif
void setSocketReuse(SOCKET fd);
void setSocketTimeout(SOCKET fd, timeval time);
std::string receive(pollfd* pfds);
bool isTimeout(int ret);
int Poll(pollfd* fds, int n);
void printError();
const int PORT = 23232;
int main()
{
#ifdef PLATFORM_WINDOWS
WSAData wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
#endif
SOCKET mainfd = socket(AF_INET, SOCK_DGRAM, 0);
timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
setSocketReuse(mainfd);
setSocketTimeout(mainfd, timeout);
sockaddr_in addr{};
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
int ret = bind(mainfd, reinterpret_cast<sockaddr*>(&addr), static_cast<int>(sizeof(sockaddr_in)));
char buffer[1024];
sockaddr from{};
#ifdef PLATFORM_WINDOWS
int fromlen = sizeof(from);
#elif defined PLATFORM_LINUX
socklen_t fromlen = sizeof(from);
#endif
pollfd pfds[2];
pfds[0].fd = mainfd;
pfds[0].events = POLLIN;
Poll(pfds, 1);
ret = recvfrom(mainfd, buffer, sizeof(buffer), 0, &from, &fromlen);
SOCKET peerfd = socket(AF_INET, SOCK_DGRAM, 0);
setSocketReuse(peerfd);
setSocketTimeout(peerfd, timeout);
ret = bind(peerfd, reinterpret_cast<sockaddr*>(&addr), static_cast<int>(sizeof(sockaddr_in)));
ret = connect(peerfd, &from, fromlen);
const char data[] = "Hello!";
ret = send(peerfd, data, sizeof(data), 0);
pfds[1].fd = peerfd;
pfds[1].events = POLLIN;
std::string out;
do
{
out = receive(pfds);
std::cout << out << std::endl;
} while (out != "exit");
closesocket(mainfd);
#ifdef PLATFORM_WINDOWS
WSACleanup();
#endif
return 0;
}
void setSocketReuse(SOCKET fd)
{
const int ON = 1;
#ifdef PLATFORM_WINDOWS
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&ON), sizeof(ON));
#elif defined(PLATFORM_LINUX)
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &ON, sizeof(ON));
#endif
}
void setSocketTimeout(SOCKET fd, timeval time)
{
#ifdef PLATFORM_WINDOWS
DWORD dw = (time.tv_sec * 1000) + ((time.tv_usec + 999) / 1000);
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&dw, sizeof(dw));
#elif defined PLATFORM_LINUX
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&time, sizeof(time));
#endif
}
std::string receive(pollfd* pfds)
{
char buffer[1024];
int ret = Poll(pfds, 2);
std::cout << "poll: " << ret << std::endl;
if (ret == -1)
printError();
ret = recv(pfds[1].fd, buffer, sizeof(buffer), 0);
if (ret >= 0 && !isTimeout(ret))
{
std::cout << "pfds[1].fd recv" << std::endl;
return buffer;
}
std::cout << "pfds[1].fd timeout" << std::endl;
ret = recv(pfds[0].fd, buffer, sizeof(buffer), 0);
if (ret >= 0 && !isTimeout(ret))
{
std::cout << "pfds[0].fd recv" << std::endl;
return buffer;
}
std::cout << "pfds[0].fd timeout" << std::endl;
return "";
}
bool isTimeout(int ret)
{
bool time;
#ifdef PLATFORM_WINDOWS
if (ret != SOCKET_ERROR)
return false;
int err = WSAGetLastError();
time = err == WSAETIMEDOUT;
#elif defined PLATFORM_LINUX
if (ret != -1)
return false;
int err = errno;
time = err == EAGAIN || err == EWOULDBLOCK;
#endif
if (!time)
printError();
return time;
}
int Poll(pollfd* fds, int n)
{
#ifdef PLATFORM_WINDOWS
return WSAPoll(fds, n, -1);
#elif defined PLATFORM_LINUX
return poll(fds, n, -1);
#endif
}
void printError()
{
#ifdef PLATFORM_WINDOWS
int err = WSAGetLastError();
wchar_t* s = NULL;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&s, 0, NULL);
std::wcerr << s << " (" << err << ")" << std::endl;
LocalFree(s);
#elif defined PLATFORM_LINUX
int err = errno;
std::cerr << strerror(err) << " (" << err << ")" << std::endl;
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment