Skip to content

Instantly share code, notes, and snippets.

@Flamefire
Last active July 24, 2018 10:49
Show Gist options
  • Save Flamefire/0340a8fc56506cc8a1f4c52e91c5b0f5 to your computer and use it in GitHub Desktop.
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`
#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