2017년 12월 4일 월요일

Client socket programming using select api in linux written by C language

#include
#include
#include
#include
#include
#include

#define SELMAXSOCK (16)
#define SELTIMEO (10)

int get_connected_sock(char *target, char *service);
int connect_select(struct addrinfo* addr);

int main(int argc, char **argv) {
int sockd;

sockd = get_connected_sock("www.google.com", "1234");

/*
* do something using connected socket descriptor.
*
* ...
* ...
* close(sockd);
*
*/

return 0;
}

int get_connected_sock(char *target, char *service) {
int sockd;
struct addrinfo hints;
struct addrinfo *addrlist;

memset(&hints, 0, sizeof(struct addrinfo));

hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;

if (getaddrinfo(target, service, &hints, &addrlist) == -1)
return -1;

sockd = connect_select(addrlist);

freeaddrinfo(addrlist);

return sockd;
}

int connect_select(struct addrinfo* addr) {
int active_sock_cnt, err, rtn, i, j;
int sock_fd[SELMAXSOCK];
uint sock_flags[SELMAXSOCK];
socklen_t sock_len;
fd_set rset, wset;
struct timeval tv;

FD_ZERO(&rset);

for (i = 0; addr != NULL && i < SELMAXSOCK; addr = addr->ai_next) {
if ((sock_fd[i] = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) == -1) {
// socket creating failed
continue;
}

sock_flags[i] = fcntl(sock_fd[i], F_GETFL, 0);
fcntl(sock_fd[i], F_SETFL, sock_flags[i] | O_NONBLOCK); // set non-nonblocking option to socket

if (connect(sock_fd[i], addr->ai_addr, addr->ai_addrlen) == 0) {
// connect success immediately
for (j = 0; j < i; j++) {
rtn = close(sock_fd[j]);
// close already created sockets
}

fcntl(sock_fd[i], F_SETFL, sock_flags[i]);
return sock_fd[i];
} else {
if (errno != EINPROGRESS) {
// connect failed, close socket
rtn = close(sock_fd[i]);
continue;
}

// connecting in progress. this is target to select()
FD_SET(sock_fd[i], &rset);
i++;
}

}

active_sock_cnt = i;

wset = rset;
tv.tv_sec = SELTIMEO;
tv.tv_usec = 0;

if (select(sock_fd[active_sock_cnt - 1] + 1, &rset, &wset, NULL, &tv) == 0) {
// select timeout

for (i = 0; i < active_sock_cnt; i++) {
rtn = close(sock_fd[i]);
// close already created sockets
}

return -1;
}

for (i = 0; i < active_sock_cnt; i++) {
if (FD_ISSET(sock_fd[i], &rset) || FD_ISSET(sock_fd[i], &wset)) {
sock_len = sizeof(err);
err = 0;

if (getsockopt(sock_fd[i], SOL_SOCKET, SO_ERROR, &err, &sock_len) < 0) {
// getsockopt function error. close socket
rtn = close(sock_fd[i]);
continue;
}

if (err) {
// socket error. close socket
rtn = close(sock_fd[i]);
continue;
}
} else {
// read/write descriptor is not set
rtn = close(sock_fd[i]);
continue;
}

// now, we get successful connected socket

for (j = i + 1; j < active_sock_cnt; j++) {
// close already created sockets
rtn = close(sock_fd[j]);
}

fcntl(sock_fd[i], F_SETFL, sock_flags[i]);
return sock_fd[i];
}

return -1;
}

댓글 없음:

댓글 쓰기