Related
I am trying to connect to the local openvpn client over its managment socket and query its state/status.
I have implemented the follow program with libevent support.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <event2/event.h>
#include <fcntl.h>
#include <string.h>
char message[1000], server_reply[2000];
struct event *ev, *ev1, *ev2;
int fd_set_blocking(int fd, int blocking)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
return 0;
}
if (blocking) {
flags &= ~O_NONBLOCK;
} else {
flags |= O_NONBLOCK;
}
return fcntl(fd, F_SETFL, flags) != -1;
}
void cb_func_hold_release(evutil_socket_t fd, short what, void *arg)
{
int sock = *(int *)arg;
struct timeval one_seconds = {1,0};
printf("IN CB CONNECT\n");
sprintf (message, "hold release\n");
if (send (sock, message, strlen (message), 0) < 0) {
printf("send failed\n");
}
event_add(ev1, NULL);
}
void cb_func_write(evutil_socket_t fd, short what, void *arg)
{
int sock = *(int *)arg;
printf("IN CB CHECKSTATUS\n");
sprintf (message, "status\n");
if (send (sock, message, strlen (message), 0) < 0) {
printf("send failed\n");
}
/*
int reclen = recv (sock, server_reply, 2000, 0);
if (reclen < 0) {
printf("recving failed");
} else {
if (reclen > 1) {
server_reply[reclen-1] = '\0';
}
printf("SERVER REPLT< %s\n", server_reply);
}
if (strstr(message, "CONNECTED")) {
printf("VPN CONNECTED");
}
*/
event_add(ev2, NULL);
if (event_pending(ev2,EV_READ|EV_PERSIST, NULL)) {
printf("ADDED READ EVENT\n");
}
}
void cb_func_read(evutil_socket_t fd, short what, void *arg)
{
int sock = *(int *)arg;
printf("IN CB READ\n");
int reclen = recv (sock, server_reply, 2000, 0);
if (reclen < 0) {
printf("recving failed");
} else {
if (reclen > 1) {
server_reply[reclen-1] = '\0';
}
printf("SERVER REPLY %s\n", server_reply);
}
if (strstr(message, "CONNECTED")) {
printf("VPN CONNECTED");
}
}
int main(void)
{
int flags;
int mgmretry = 0;
int sock = 0;
struct sockaddr_in server;
struct timeval five_seconds = {1,0};
struct event_base *base = event_base_new();
ev = event_new(base, sock, EV_TIMEOUT, cb_func_hold_release, &sock);
ev1 = event_new(base, sock, EV_WRITE, cb_func_write, &sock);
ev2 = event_new(base, sock, EV_READ, cb_func_read, &sock);
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("COUILD NOT CREATE SOCKET\n");
exit(0);
}
fd_set_blocking(sock, 1);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons (12345);
if (connect (sock, (struct sockaddr *)&server, sizeof (server)) < 0) {
printf("connecting failed\n");
exit(0);
}
event_add(ev, &five_seconds);
printf("DISPATCHING\n");
event_base_dispatch(base);
}
The issue is the the read callback "cb_func_read" is not being triggered. My expectation is that after I send the "status" message to the vpn from cb_func_write(), there is some data sent back which should trigger the read callback but that's not happening.
If I recv() directly after send() in the write callback(the commented portion) I can print the response sent from openvpn so the communication between these two are working.
The event will not trigger unless you armed it using event_add().
You have only done this for the ev event, but not for ev1 and ev2.
silly ,mistake...events ev,ev1,ev2 with event_new() come AFTER creating a socket+making it nonblock... not before
I have read some example and manual about select and accept but I still can't figure out where I did wrong.
I tried to let server communicate with multiple clients. But when I execute server first, then execute client, server will immediately cause segmentation fault( when i == sockfd in server.c). And I tried to print some strings to check which statement cause wrong, it even no print anything after if (i == sockfd). So I really have no idea how to move on, are there any suggestion?
Server.c
char inputBuffer[140] = {};
char message[] = {"Hi,this is server.\n"};
int sockfd = 0,forClientSockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket creation
struct sockaddr_in serverInfo,clientInfo;
socklen_t addrlen = sizeof(clientInfo);
serverInfo.sin_family = PF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_port = htons(PORT);
bind(sockfd,(struct sockaddr *)&serverInfo,sizeof(serverInfo));
listen(sockfd,5);
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in clientname;
size_t size;
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sockfd, &active_fd_set);
int fd_max = sockfd;
while (1)
{
/* Block until input arrives on one or more active sockets. */
//FD_ZERO (&active_fd_set);
//FD_SET (sockfd, &active_fd_set);
read_fd_set = active_fd_set;
if (select (fd_max+1, &read_fd_set, NULL, NULL, NULL) < 0)
{
printf("select fail\n");
}
/* Service all the sockets with input pending. */
for (i = 0; i <= fd_max; ++i)
{
//printf("%d\n",i);
if (FD_ISSET (i, &read_fd_set))
{
//printf("inner :%d %d\n",i,sockfd);
if (i == sockfd)
{
/* Connection request on original socket. */
//printf("A");
int new;
size = sizeof (clientname);
new = accept (sockfd,(struct sockaddr *) &clientname,&size);
if (new < 0)
{
printf("accept fail\n");
}
else
{
printf (
"Server: connect from host %s, port %hd.\n",
inet_ntoa (clientname.sin_addr),
ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
if(new > fd_max)
{
fd_max = new;
}
}
}
else
{
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0)
{
close (i);
FD_CLR (i, &active_fd_set);
}
}
}
}
}
return 0;
}
int read_from_client (int filedes)
{
char buffer[140];
int nbytes;
nbytes = recv (filedes, buffer, sizeof(buffer),0);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else
{
/* Data read. */
printf ("Server: got message: `%s'\n", buffer);
return 0;
}
}
client.c
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket connnection
struct sockaddr_in info;
bzero(&info,sizeof(info));
info.sin_family = PF_INET;
//localhost test
info.sin_addr.s_addr = inet_addr(LOCALHOST);
info.sin_port = htons(PORT);
int err;
char *p;
//Send a message to server
err = connect(sockfd,(struct sockaddr *)&info,sizeof(info));
if(err==-1)
printf("Connection error");
while(1)
{
char message[140];
char receiveMessage[140] = {};
fgets(message,140,stdin);
//scanf("%*[^\n]",message);
//printf("%s",message);
/*if(p=strchr(message,'\n')){
*p = 0;
}else{
scanf("%*[^\n]");
scanf("%c");
}
fgets(message,140,stdin);*/
//scanf("%s",message);
send(sockfd,message,sizeof(message),0);
//printf("RCV");
//recv(sockfd,receiveMessage,sizeof(receiveMessage),0);
//printf("%s\n",receiveMessage);
}
thanks !!
I'm trying to connect 10,000+ tcp clients to my tcp server below. After 1-5 seconds I'm able to get between 200 and 5000 clients connected before the code grinds to a halt and hangs without terminating. I cant find any further documentation on this and the gprof profiler isnt able to collect any data.
Server:
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netdb.h>
#include <errno.h>
#include <iostream>
#ifndef MAXEVENTS
#define MAXEVENTS 64
#endif
#ifndef TX_BUF_SIZE
#define TX_BUF_SIZE (65535)
#endif
#ifndef RX_BUF_SIZE
#define RX_BUF_SIZE (65535)
#endif
char buf[RX_BUF_SIZE];
void user_recv_handler(int efd, int fd, char * buf, int len)
{
int s = -1;
struct epoll_event ev;
ev.data.fd = fd;
ev.events = EPOLLOUT | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev);
//assert(s!=-1);
if(s==-1)
{
fprintf(stderr, "epoll out error.\n");
return;
}
}
struct addrinfo* tcpipv4_getaddrinfo(char* port)
{
struct addrinfo hints;
struct addrinfo *res;
int s;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // ipv4 addrs
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port, &hints, &res);
//assert(s==0);
if (s)
{
fprintf(stderr, "failed to getaddrinfo: %s\n", gai_strerror(s));
return NULL;
}
return res;
}
struct addrinfo* tcpipv6_getaddrinfo(char* port)
{
struct addrinfo hints;
struct addrinfo *res;
int s;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET6; // ipv4 addrs
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port, &hints, &res);
//assert(s==0);
if (s)
{
fprintf(stderr, "failed to getaddrinfo-ipv6: %s\n", gai_strerror(s));
return NULL;
}
return res;
}
int set_nonblock(int fd)
{
int flags = -1;
if(-1 == (flags = fcntl(fd, F_GETFL, 0)))
{
return -1;
}
flags |= O_NONBLOCK;
if( fcntl(fd, F_SETFL, flags) == -1 )
{
return -1;
}
return 0;
}
int tcpipv4_createfd_bind(struct addrinfo* rp)
{
int flags = -1;
int s;
// create socket
int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
//assert(sfd!=-1);
if (sfd == -1)
{
fprintf(stderr, "failed to create socket\n");
return -1;
}
// bind
s = bind(sfd, rp->ai_addr, rp->ai_addrlen);
//assert(s==0);
if(s!=0)
{
fprintf(stderr, "failed to bind socket %d\n", sfd);
return -1;
}
// nonblock
s = set_nonblock(sfd);
//assert(s != -1);
if (s == -1)
{
fprintf(stderr, "failed to set nonblocking socket %d\n", sfd);
return -1;
}
return sfd;
}
int writen(int fd, char * buf, size_t len)
{
char * cur = buf;
int n = -1;
while(len>0)
{
n = write(fd, cur, len);
if (n<=0)
{
if(errno == EINTR) continue;
else return -1;
}
len -= n;
cur += n;
}
return 0;
}
int readn(int fd, char* buf, size_t len)
{
char *cur = buf;
int n = -1;
while (len>0)
{
n = read(fd, cur, len);
if (n == -1)
{
if (errno == EINTR)
continue;
else break;
}
else if (n == 0)
break;
cur += n; len -= n;
}
return (int)(cur-buf);
}
void accept_handler(int efd, int listenfd)
{
struct epoll_event event;
int s;
while(1)
{
struct sockaddr in_addr;
socklen_t in_addrlen = sizeof(struct sockaddr);
int infd = -1;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
infd = accept(listenfd, &in_addr, &in_addrlen);
//assert(infd != -1);
if(infd == -1)
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
;
else
perror("failed to accept\n");
return;
}
s = getnameinfo(&in_addr, in_addrlen,
hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV);
//assert(s == 0);
if(s == 0)
{
printf("Accept fd %d host %s port %s\n", infd, hbuf, sbuf);
s = set_nonblock(infd);
//assert(s!=-1);
event.data.fd = infd;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event);
//assert(s != -1);
return;
}
}
return;
}
void read_handler(int efd, int fd)
{
//do sonething with buf.
int s = -1;
s=readn(fd, buf, sizeof(buf));
buf[s] = 0;
//printf("recv %d bytes: %s", s, buf);
if(s < 0)
{
close(fd);
if(-1 == epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) )
fprintf(stderr, "failed to del event of %d\n", fd);
printf("close conection on fd %d", fd);
}
else if(s > 0)
{
//std::cout << buf << std::endl;
//do sonething with buf.
user_recv_handler(efd, fd, buf, s);
}
}
void write_handler(int efd, int fd)
{
writen(fd, buf, strlen(buf));
if(-1 == epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) )
fprintf(stderr, "failed to del event of %d\n", fd);
// close(fd);
}
int main(int argc, char ** argv)
{
char* port = NULL;
int listenfd = -1;
struct addrinfo* hostaddr=NULL;
struct addrinfo* rp = NULL;
struct epoll_event event;
struct epoll_event * events, *cur_ev;
int efd = -1;
int num_ev = -1;
int s;
port = argv[1];
// get server ipv4 address by getaddrinfo
(rp = hostaddr = tcpipv4_getaddrinfo(port));
// create and bind listening socket
for(; rp; rp = rp->ai_next)
{
(listenfd = tcpipv4_createfd_bind(rp));
if(-1 == listenfd)
continue;
}
freeaddrinfo(hostaddr);
//assert(listenfd!=-1);
if(listenfd==-1)
exit(EXIT_FAILURE);
//start listening
(s = listen(listenfd, SOMAXCONN));
//assert(s!=-1);
if(s == -1)
exit(EXIT_FAILURE);
// create epoll
efd = epoll_create(MAXEVENTS);
//assert(efd != -1);
if(efd == -1)
exit(EXIT_FAILURE);
event.data.fd = listenfd;
// epoll: read, ET
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &event);
//assert(s!=-1);
if(s==-1)
exit(EXIT_FAILURE);
events = (struct epoll_event*)calloc(MAXEVENTS, sizeof(struct epoll_event));
// event loop;
while (1)
{
num_ev = epoll_wait(efd, events, MAXEVENTS, -1);
// for each active event:
while(num_ev--)
{
cur_ev = events+num_ev;
// close the fd if error (ERR) or hang up (HUP)
if(cur_ev->events & EPOLLERR ||
cur_ev->events & EPOLLHUP)
{
fprintf(stderr, "epoll get event error\n");
close(cur_ev->data.fd);
continue;
}
// one or more new connections (fd = listenfd)
else if(cur_ev->data.fd == listenfd)
{
accept_handler(efd, listenfd);
continue;
}
else if(cur_ev->events & EPOLLIN)
{
// since the registered event is EPOLLIN,
// here we have data on fd waiting for reading.
read_handler(efd, cur_ev->data.fd);
}
else if (cur_ev->events & EPOLLOUT)
{
write_handler(efd, cur_ev->data.fd);
}
}
}
free(events); events = NULL;
close(listenfd);
exit(EXIT_SUCCESS);
}
Client:
int connected_count=0;
int i=0;
struct timespec tstart={0,0}, tend={0,0};
clock_gettime(CLOCK_MONOTONIC, &tstart);
for(; i!=10000; i++)
{
int sockfd;
int portno = 4000;
ssize_t n;
struct sockaddr_in serveraddr;
struct hostent* server;
char hostname[] = "127.0.0.1";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
printf("ERROR opening socket");
printf("error %d",errno);
test_function_killall(NULL);
return;
}
server = gethostbyname(hostname);
if(server == NULL)
{
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
test_function_killall(NULL);
return;
}
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char*)server->h_addr, (char*)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
printf("ERROR connecting");
test_function_killall(NULL);
return;
}
else
{
std::cout << "active connections " << connected_count++ << std::endl;
}
set_nonblock(sockfd);
}
if(connected_count==10000)
{
printf("complete");
}
Start with this:
Remove the EPOLLET flags from the listen socket registration. You
might want to remove it from the client connection sockets too.
Set your listen socket to non-blocking similar to how the client
connection sockets returned from accept are set.
There's all kinds of edge cases with the listen sockets. I'm not sure, but it appears you aren't fully draining the accept queue when epoll_ctl comes back to indicate that the listen socket has a connection ready. (Think: multiple incoming connections on one edge trigger). It's possible you are blocking on accept and/or stuck on epoll_wait.
Update:
Another thing you could be hitting are the system limits for the maximum number of files handles per process. Read up here.
i am creating a simple tcp echo server in c using epoll. while compiling it gives error:
Socket operation on non-socket
why does it gives non-socket? i tried but couldn't get my head around it.
below is my code and here is the article that i am following
my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include <unistd.h>
#define MAX_LISTEN_BACKLOG 1
#define BUFFER_SIZE 4096
int bind_and_create(char *port){
struct addrinfo hints;
struct addrinfo *result, *rp;
int s, sfd;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port , &hints, &result);
if( s != 0 ){
fprintf(stderr,"getaddrinfo :%s\n",gai_strerror(s));
return -1;
}
for( rp = result; rp!= NULL; rp->ai_next){
int sfd = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);
if ( sfd == -1)
continue;
s = bind(sfd, rp->ai_addr,rp->ai_addrlen);
if ( s == 0){
//succefull managed to bind socket
break;
}
close(sfd);
}
if ( rp == NULL){
fprintf(stderr,"could not bind");
}
freeaddrinfo(result);
return sfd;
}
int make_socket_non_blocking( int sfd ){
int flags , s;
flags = fcntl(sfd, F_GETFL, 0);
if (flags == -1){
perror("fnctl error");
return -1;
}
flags |= O_NONBLOCK;
s = fcntl(sfd,F_SETFL,flags);
if (s == -1){
perror("fnctl error");
return -1;
}
return 0;
}
#define MAXEVENTS 64
int main (int argc, char *argv[])
{
int sfd, s;
int efd;
struct epoll_event event;
struct epoll_event *events;
if (argc != 2)
{
fprintf (stderr, "Usage: %s [port]\n", argv[0]);
exit (EXIT_FAILURE);
}
sfd = bind_and_create (argv[1]);
if (sfd == -1)
abort ();
s = make_socket_non_blocking (sfd);
if (s == -1)
abort ();
s = listen (sfd, SOMAXCONN); // error is here but why????
if (s == -1)
{
perror ("listen");
abort ();
}
efd = epoll_create1 (0);
if (efd == -1)
{
perror ("epoll_create");
abort ();
}
event.data.fd = sfd;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
if (s == -1)
{
perror ("epoll_ctl");
abort ();
}
/* Buffer where events are returned */
events = calloc (MAXEVENTS, sizeof event);
/* The event loop */
while (1)
{
int n, i;
n = epoll_wait (efd, events, MAXEVENTS, -1);
for (i = 0; i < n; i++)
{
if ((events[i].events & EPOLLERR) ||
(events[i].events & EPOLLHUP) ||
(!(events[i].events & EPOLLIN)))
{
/* An error has occured on this fd, or the socket is not
ready for reading (why were we notified then?) */
fprintf (stderr, "epoll error\n");
close (events[i].data.fd);
continue;
}
else if (sfd == events[i].data.fd)
{
/* We have a notification on the listening socket, which
means one or more incoming connections. */
while (1)
{
struct sockaddr in_addr;
socklen_t in_len;
int infd;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
in_len = sizeof in_addr;
infd = accept (sfd, &in_addr, &in_len);
if (infd == -1)
{
if ((errno == EAGAIN) ||
(errno == EWOULDBLOCK))
{
/* We have processed all incoming
connections. */
break;
}
else
{
perror ("accept");
break;
}
}
s = getnameinfo (&in_addr, in_len,
hbuf, sizeof hbuf,
sbuf, sizeof sbuf,
NI_NUMERICHOST | NI_NUMERICSERV);
if (s == 0)
{
printf("Accepted connection on descriptor %d "
"(host=%s, port=%s)\n", infd, hbuf, sbuf);
}
/* Make the incoming socket non-blocking and add it to the
list of fds to monitor. */
s = make_socket_non_blocking (infd);
if (s == -1)
abort ();
event.data.fd = infd;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
if (s == -1)
{
perror ("epoll_ctl");
abort ();
}
}
continue;
}
else
{
/* We have data on the fd waiting to be read. Read and
display it. We must read whatever data is available
completely, as we are running in edge-triggered mode
and won't get a notification again for the same
data. */
int done = 0;
while (1)
{
ssize_t count;
char buf[512];
count = read (events[i].data.fd, buf, sizeof buf);
if (count == -1)
{
/* If errno == EAGAIN, that means we have read all
data. So go back to the main loop. */
if (errno != EAGAIN)
{
perror ("read");
done = 1;
}
break;
}
else if (count == 0)
{
/* End of file. The remote has closed the
connection. */
done = 1;
break;
}
/* Write the buffer to standard output */
s = write (1, buf, count);
if (s == -1)
{
perror ("write");
abort ();
}
}
if (done)
{
printf ("Closed connection on descriptor %d\n",
events[i].data.fd);
/* Closing the descriptor will make epoll remove it
from the set of descriptors which are monitored. */
close (events[i].data.fd);
}
}
}
}
free (events);
close (sfd);
return EXIT_SUCCESS;
}
int bind_and_create(char *port){
...
int s, sfd; // <- one sfd
...
for( rp = result; rp!= NULL; rp->ai_next){ // <- rp->ai_next has no effect
int sfd = socket(...); // <-- two sfd
...
close(sfd); // <-- two sfd gone
}
...
return sfd; // <-- one sfd, still completely uninitialised
}
If you want to stop wasting your time on this, use -Wall or an equivalent compiler setting.
I am trying to use the select function to have non-blocking i/o between a server and 1 client (no more) where the communication flows nicely (can send at any time and the other will receive without waiting to send). I found a tutorial with some code and tried to adapt it to mine. This is what I have -
Server
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!";
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
if(strlen(out) != 0)
FD_SET(new_sd, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
FD_CLR(new_sd, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(new_sd, in, sizeof(in), 0) <= 0) {
close(new_sd);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
FD_CLR(new_sd, &write_flags);
send(new_sd, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
Client (basically the same just minus an accept call) -
#define PORT "4950"
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection!";
set_nonblock(sock);
char* out = new char[255];
char* in = new char[255];
int numRead;
int numSent;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(sock, &read_flags);
if(strlen(out) != 0)
FD_SET(sock, &write_flags);
sel = select(sock+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(sock, &read_flags)) {
FD_CLR(sock, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(sock, in, sizeof(in), 0) <= 0) {
close(sock);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(sock, &write_flags)) {
FD_CLR(sock, &write_flags);
send(sock, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The problem is that when I run them, nothing happens. I can type into one and hit enter and nothing shows up on the other screen (and vice versa). Thats not a whole of information for me to debug and this is my first real attempt at using select so I thought maybe I am just unaware of something simple. If anything can be spotted as wrong or weird please point it out, any help is appreciated.
The problem is that when I run them, nothing happens.
The real problem is that people have been pasting stuff from Beej for years without understanding it. That's why I don't really like that guide; it gives large blocks of code without really explaining them in detail.
You're not reading anything and not sending anything; no fgets, scanf, cin, etc. Here's what I would do:
FD_SET(sock, &read_flags);
FD_SET(STDIN_FILENO, &read_flags);
/* .. snip .. */
if(FD_ISSET(STDIN_FILENO, &read_flags)) {
fgets(out, len, stdin);
}
This will monitor stdin and read from it when input is available; then, when the socket is writeable (FD_ISSET(sock, &write_flags)), it will send the buffer.
I have the program working correctly now.
server -
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd = {10, 0}; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
//set non blocking
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!\n";
char in[255];
char out[255];
memset(&in, 0, 255);
memset(&out, 0, 255);
int numSent;
int numRead;
while(1) {
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
FD_SET(new_sd, &write_flags);
FD_SET(STDIN_FILENO, &read_flags);
FD_SET(STDIN_FILENO, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
//if an error with select
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
//clear set
FD_CLR(new_sd, &read_flags);
memset(&in, 0, 255);
numRead = recv(new_sd, in, 255, 0);
if(numRead <= 0) {
printf("\nClosing socket");
close(new_sd);
break;
}
else if(in[0] != '\0')
cout<<"\nClient: "<<in;
} //end if ready for read
//if stdin is ready to be read
if(FD_ISSET(STDIN_FILENO, &read_flags))
fgets(out, 255, stdin);
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
//printf("\nSocket ready for write");
FD_CLR(new_sd, &write_flags);
send(new_sd, out, 255, 0);
memset(&out, 0, 255);
} //end if
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The client is basically the same...only difference really is the lack of listen and accept.
I just want to add that above example may not work as expected on Linux. On Linux waitd may be modified by select. So for Linux, waitd should be rewritten before select.
See the "timeout" section in the man page for select.