Last active
June 23, 2022 20:32
-
-
Save GurixD/becb340fcee09ce2fec24718373688eb to your computer and use it in GitHub Desktop.
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 <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; | |
} | |
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 <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