Last active
July 24, 2018 10:49
-
-
Save Flamefire/0340a8fc56506cc8a1f4c52e91c5b0f5 to your computer and use it in GitHub Desktop.
Test for sockets. Compile with `g++ main.cpp -DUSE_THREAD=0 -std=c++11`
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 <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <netinet/tcp.h> | |
#include <sys/socket.h> | |
#include <sys/ioctl.h> | |
#include <netdb.h> | |
#include <unistd.h> | |
#include <cassert> | |
#include <cstring> | |
#include <iostream> | |
#include <thread> | |
bool SetSockOpt(int socket_, int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel) | |
{ | |
return (-1 != setsockopt(socket_, nLevel, nOptionName, (char*)lpOptionValue, nOptionLen)); | |
} | |
bool running = true; | |
void runServer(int socket){ | |
std::cout << "Started server" << std::endl; | |
while(running){ | |
fd_set set; | |
FD_ZERO(&set); | |
FD_SET(socket, &set); | |
timeval tv; | |
tv.tv_sec = 0; | |
tv.tv_usec = 0; | |
if(select(socket + 1, &set, NULL, NULL, &tv) <= 0) | |
continue; | |
int connfd = accept(socket, (struct sockaddr*)NULL, NULL); | |
if(connfd == -1) | |
continue; | |
std::cout << "Got client" << std::endl; | |
close(connfd); | |
} | |
} | |
int main() | |
{ | |
uint16_t port = 1234; | |
int sock = socket(AF_INET, SOCK_STREAM, 0); | |
assert(sock != -1); | |
int disable = 1; | |
assert(SetSockOpt(sock, TCP_NODELAY, &disable, sizeof(int), IPPROTO_TCP)); | |
int enable = 1; | |
assert(SetSockOpt(sock, SO_REUSEADDR, &enable, sizeof(int), SOL_SOCKET)); | |
sockaddr_in addrs; | |
addrs.sin_family = AF_INET; | |
addrs.sin_port = htons(port); | |
addrs.sin_addr.s_addr = INADDR_ANY; | |
int size = sizeof(addrs); | |
assert(bind(sock, (sockaddr*)&addrs, size) != -1); | |
listen(sock, 10); | |
#if USE_THREAD | |
std::thread serverThread(runServer, sock); | |
#endif | |
int clientSock = socket(AF_INET, SOCK_STREAM, 0); | |
assert(clientSock != -1); | |
assert(SetSockOpt(clientSock, TCP_NODELAY, &disable, sizeof(int), IPPROTO_TCP)); | |
assert(SetSockOpt(clientSock, SO_REUSEADDR, &enable, sizeof(int), SOL_SOCKET)); | |
unsigned long argp = 1; | |
ioctl(clientSock, FIONBIO, &argp); | |
sockaddr_in addr4; | |
memset(&addr4, 0, sizeof(addr4)); | |
addr4.sin_family = AF_INET; | |
addr4.sin_port = htons(port); | |
addr4.sin_addr.s_addr = inet_addr("127.0.0.1"); | |
int res = connect(clientSock, (sockaddr*) &addr4, sizeof(addr4)); | |
if(res != -1){ | |
std::cout << "Connected on first try!" << std::endl; | |
}else if(errno == EINPROGRESS){ | |
unsigned timeInMs = 0; | |
while(true){ | |
fd_set sw, se; | |
FD_ZERO(&sw); | |
FD_ZERO(&se); | |
FD_SET(clientSock, &sw); | |
FD_SET(clientSock, &se); | |
timeval tv; | |
tv.tv_sec = 0; | |
tv.tv_usec = 0; | |
if(select(clientSock + 1, NULL, &sw, NULL, &tv) == 1 || select(clientSock + 1, NULL, NULL, &se, &tv) != 0){ | |
unsigned err; | |
socklen_t len = sizeof(err); | |
getsockopt(clientSock, SOL_SOCKET, SO_ERROR, (char*)&err, &len); | |
if(err){ | |
std::cout << "Got error: " << err << std::endl; | |
break; | |
} | |
std::cout << "Connected after " << timeInMs << "ms" << std::endl; | |
break; | |
} | |
if(timeInMs += 50 > 10000){ | |
std::cout << "Timeout after " << timeInMs << "ms" << std::endl; | |
break; | |
} | |
usleep(50 * 1000); | |
} | |
} | |
sleep(2); | |
running = false; | |
#if USE_THREAD | |
serverThread.join(); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment