The program creates n threads for simulating n nodes in a distributed system, each has one socket it listens to and each thread can communicate to n-1 other threads through connect calls.
Each thread makes a call to select() to see if anything's available and if so accepts and saves the data.
I use ioctl with the flag FIONREAD to check the number of bytes available to be read and do an appropriate read call. Afterwards the new fd (from accept()) is closed.
The listening sockets are blocking. O_NONBLOCK is NOT set.
All n threads run the same function. All variables declared within the function use thread local storage.
There's no explicit synchronization done on my part. More than one thread can try to connect to the same socket at once.
Now, the problem is, once in a while, the select() in a thread on the receiving side notes something new but the amount of bytes available is 0 which it shouldn't be. This happens inconsistently.
Would be great if someone can point where I should look into. Thanks!
creating the sock
if ( (nptr->sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
fd_max = nptr->sock > fd_max ? nptr->sock : fd_max;
int ok=1;
setsockopt(nptr->sock, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(int));
nptr->addr.sun_family = AF_UNIX;
snprintf(nptr->addr.sun_path, 20, "%d", nptr->id);
//strncpy(nptr->addr.sun_path, sock_path, 20);
if ( bind(nptr->sock, (struct sockaddr*)&(nptr->addr), sizeof(struct sockaddr_un)) < 0 ) {
perror("bind");
exit(1);
}
/* socket, max connections */
if ( listen(nptr->sock, 2*tot_node) < 0 ) {
perror("listen");
exit(1);
}
sending stuff
for (t=0; t<tot_node; t++) {
...
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Node %d: trying to req node %d... ", self->id, node_catalog[t]->id);
if ( connect(fd, (struct sockaddr*)&(node_catalog[t]->addr), sizeof(struct sockaddr_un)) == -1 ) {
perror("connect");
exit(1);
}
buf[0] = TYPE_REQ;
buf[1] = self->id;
buf[2] = ts;
buf[3] = rsc;
write (fd, buf, 4*sizeof(int));
//close(fd);
printf("Node %d: sent req for resource %d to %d\n", self->id, rsc, node_catalog[t]->id);
}
usleep(TS_UPDATE_ITV);
receiving stuff
FD_ZERO(&readset);
FD_SET(self->sock, &readset);
t = pselect(self->sock+1, &readset, NULL, NULL, &tout, NULL);
if (t > 0 && FD_ISSET(self->sock, &readset)) {
com_fd = accept(self->sock, NULL, NULL);
ioctl(com_fd, FIONREAD, &t);
#ifdef DEBUG
printf(" Node %d: received %d bytes of data\n", self->id, t);
#endif
read(com_fd, buf, t);
close(com_fd);
dptr = (int *)buf;
rsc = t / (sizeof(int)); /* var reuse. this is the count of ints to read */
for (t=0; t<rsc; ) {
static __thread int nid, nts, nrsc;
#ifdef DEBUG
printf(" Node %d: data rcvd: %d %d %d %d", self->id, *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
#endif
if (*dptr == TYPE_REQ) {
... } else {...}
Your code doesn't make sense. The reason that select() fired was that there was something to accept. Checking FIONREAD on a socket you've just accepted may or may not result in data being available. It depends entirely on whether the client has sent any. Not on the contract of select().
If you need to know whether there is something to read, you should add the accepted socket to the read-FD set, and process it in a loop: if the listening socket is readable, call accept() on it, otherwise it is an accepted socket and you should call read() on it.
Checking FIONREAD is really just a waste of time in most circumstances.
Related
I am writing a program which is supposed to act as a simple proxy between a web server and a browser. The browser connects to my proxy program and my program connects to the web server. My proxy program should simply forward all data it receives from the browser to the web server and vice-versa, without modifying the data in any way and without performing any caching.
I have managed to get a reply from a web server but how would I direct that reply to my browser? Also is there any way to put this into some sort of infinite loop where I can recv and send at will?
Edit:
I've almost got it. I just need to know how to continuously read the sockets. The program closes unexpectedly after I get the Http redirect.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#define SERVER_PORT 8080
#define SA struct sockaddr
#define MAX 80
pthread_t ptid, ptidd;
#define TRUE 1
#define FALSE 0
struct sockets_struct {
int server_sd;
int client_sd;
int new_sd;
}socks;
// Function designed to act as client.
void *client_func(void *sockets)
{
char buffer[MAX];
struct sockaddr_in servaddrr;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
int i, len, rc, on = 1;
//bzero(&servaddrr, sizeof(servaddrr));
// assign IP, PORT
servaddrr.sin_family = AF_INET;
servaddrr.sin_addr.s_addr = inet_addr("192.168.0.1");
servaddrr.sin_port = htons(80);
// connect the client socket to server socket
if (connect(socks->client_sd, (SA*)&servaddrr, sizeof(servaddrr)) != 0) {
printf(" client: connection with the server failed...\n");
exit(0);
}
else
printf(" client: connected to the remote server..\n");
do {
rc = recv(socks->client_sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" client: recv() failed\n");
}
break;
}
if (rc == 0) {
printf(" client: Connection closed\n");
break;
}
len = rc;
printf(" client: %d bytes received\n", len);
rc = send(socks->new_sd, buffer, len, 0);
if (rc < 0) {
perror(" client: send() failed");
break;
}
} while(TRUE);
}
// Function designed to act as server.
void *server_func(void *sockets)
{
int len, rc, on = 1;
int desc_ready, end_server = FALSE, compress_array = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in6 addr;
int timeout;
struct pollfd fds[200];
int nfds = 1, current_size = 0, i, j;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
rc = setsockopt(socks->server_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0) {
perror(" server: setsockopt() failed\n");
close(socks->server_sd);
exit(-1);
}
rc = ioctl(socks->server_sd, FIONBIO, (char *)&on);
if (rc < 0) {
perror(" server: ioctl() failed\n");
close(socks->server_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(socks->server_sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
perror(" server: bind() failed");
close(socks->server_sd);
exit(-1);
}
rc = listen(socks->server_sd, 32);
if (rc < 0) {
perror(" server: listen() failed");
close(socks->server_sd);
exit(-1);
}
memset(fds, 0 , sizeof(fds));
fds[0].fd = socks->server_sd;
fds[0].events = POLLIN;
timeout = (3 * 60 * 1000);
do {
printf(" server: waiting on poll()...\n");
rc = poll(fds, nfds, timeout);
if (rc < 0) {
perror(" server: poll() failed\n");
break;
}
if (rc == 0) {
printf(" server: poll() timed out. End program.\n");
break;
}
current_size = nfds;
for (i = 0; i < current_size; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN) {
printf(" server: Error! revents = %d\n", fds[i].revents);
end_server = TRUE;
break;
}
if (fds[i].fd == socks->server_sd) {
printf(" server: Listening socket is readable\n");
socks->new_sd = accept(socks->server_sd, NULL, NULL);
if (socks->new_sd < 0) {
if (errno != EWOULDBLOCK) {
perror(" server: accept() failed\n");
end_server = TRUE;
}
break;
}
printf(" server: new incoming connection - %d\n", socks->new_sd);
fds[nfds].fd = socks->new_sd;
fds[nfds].events = POLLIN;
nfds++;
}
else {
printf(" server: Descriptor %d is readable\n", fds[i].fd);
close_conn = FALSE;
do {
rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
if (rc == 0) {
printf(" server: Connection closed\n");
close_conn = TRUE;
break;
}
len = rc;
printf(" server: %d bytes received \n", len);
rc = send(socks->client_sd, buffer, len, 0);
if (rc < 0) {
perror(" server: send() failed\n");
close_conn = TRUE;
break;
}
} while(TRUE);
if (close_conn) {
close(fds[i].fd);
fds[i].fd = -1;
compress_array = TRUE;
}
} /* End of existing connection is readable */
} /* End of loop through pollable descriptors */
} while (end_server == FALSE); /* End of serving running. */
}
int main (int argc, char *argv[])
{
socks.server_sd = socket(AF_INET, SOCK_STREAM, 0);
socks.client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (socks.server_sd == -1) {
printf("socket \"server_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"server_sd\" successfully created..\n");
if (socks.client_sd == -1) {
printf("socket \"client_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"client_sd\" successfully created..\n");
pthread_create(&ptidd, NULL, &client_func, &socks);
pthread_create(&ptid, NULL, &server_func, &socks);
pthread_join(ptidd, NULL);
return 0;
}
You can either write a proxy that understands the data it's proxying or one that doesn't. Your question suggests that you want to write one that doesn't. That is definitely the easier approach.
So once all the connections are setup, you have two things to do. You need to read data from one connection and send it to the other. You also need to read data from the other connection and send it to the first one.
Using two threads is an easy way to do this. You can also fork a process for each direction. But the first way that everyone learns is a select or poll loop. You can punch "select loop proxy" into your favorite search engine to find lots of examples.
NOTE: This answer was written at a time before the OP edited the question and added threads to the code in the question.
The main problem I see with your algorithm is that you seem to assume that you will always receive all data from the client and server in one recv or read call. This cannot be relied upon, even if the web client (browser) only sends a single HTTP request (which is very unlikely, even if only one web page gets loaded).
I suggest you use the following algorithm instead:
Wait for web client (browser) to establish connection to your program.
Create a new socket which connects to web server.
Wait for web server connection to be established. This step is not necessary with your program, as you are using a blocking connect call. It is only necessary if non-blocking or asynchronous sockets are used.
Wait for new data to be available to be read on either of the two sockets, for example by using the function select. When this function returns, it will indicate on which sockets a non-blocking call to recv is possible.
Read from the socket(s) that select reports as having data available to be read, and write this data to the other socket using the send function.
Go to step 4.
However, this algorithm has one possible problem: It assumes that send will always be successful at writing all the bytes immediately, without blocking. Depending on the circumstances (for example the operating system's buffering of sockets) this may not always be the case. It may only be able to partially send the contents of the buffer at once. The documentation of the function send does not specify what will happen if the buffer of the send function is too large to be sent at once, i.e. whether it will block until all the data is sent or whether it will return as soon as it was able to perform a partial send.
Therefore, your algorithm should be able to deal with the case that the data is only partially sent, for example by also checking in step 4 whether it is possible to write more data if not all data was written in a previous call to send.
Also, beware that while your program is blocking on a send call, it will not process any communication in the other direction. For example, while your program is blocking on a send call while forwarding data from the client to the server, it will be unable to forward any data from the server to the client. I don't think that this can cause trouble with the HTTP protocol, because the client and server never send data simultaneously, as the server always waits for the client to finish its request and the client then waits for the server to finish its reply, before it sends another request. However, this may be an issue with other protocols. In particular, if you block communication completely in one direction, this may cause the client or server to get stuck on a blocking send or recv call, too. This could cause a deadlock in all three programs.
Therefore, you may want to consider using non-blocking sockets or asynchronous sockets instead, so that you can continue forwarding network traffic in both directions at all times.
Alternatively, you could continue using blocking socket calls and create two threads, one for forwarding data from the client to the server and one for forwarding data from the server to the client. That way, communication will never be blocked in any direction. But I would recommend using non-blocking sockets or asynchronous socket instead, as threads can get messy.
One thing your algorithm should also do is handle an orderly socket shutdown (indicated by recv returning 0) and error conditions. How to do this depends on what kind of sockets you are using, i.e. whether they are blocking, non-blocking or asynchronous.
I'm trying to write a program which either reads from a socket or from stdin. If socket then print to stdout (to user), otherwise print to socket. So far I'm using poll to awake program when there's activity on either, my problem is that after the initial connection, poll always reports activity on the socket, even though client hasn't written anything else.
Is there any way to distinguish between "someone has connected to the socket" and "someone put a message on the channel"? Looking through man pages for poll, select and others I don't really see an appropriate flag.
If there is no appropriate flag, what would be a way to accomplish what I'm trying to do ?
What I currently have is something like below. When I enter something in stdin, poll returns and the loop determines the activity was on the socket (wrong).
edit: There's other issues at well but this is what I'm struggling with right now.
/* blocking accept for first and only connection */
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
/* poll stdin and newsockfd */
struct pollfd fds[2];
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
fds[1].fd = newsockfd;
fds[1].events = POLLIN;
ioctl(newsockfd, FIONBIO, (char *)&on); /* int on = 1 */
while (1) {
int rc = poll(fds, 2, -1);
if (rc <= 0)
exit(1);
for (int i = 0; i < 2; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN)
exit(1);
if (fds[i].fd = newsockfd) {
n = read(newsockfd, buffer, 255);
printf("read %d chars from newsockfd: %s\n", n, buffer);
} else if (fds[i].fd = STDIN_FILENO) {
read(STDIN_FILENO, buffer, 255);
n = dprintf(newsockfd, "%s", buffer);
printf("wrote %d chars to newsockfd: %s\n", n, buffer);
}
}
}
I'm trying to implement a simple multi-threaded client/server program: the client sends the server a number and the server creates a thread that sends back the number+1.
The problem is as follows:
The client connects to the server with no problems;
The thread is (as far as i can tell) created without issues; But after the client writes the number in the socket, the server simply doesn't see it. The call to read() gives no errors, it just sits there, waiting forever.
I tried sending more than one integer through it; no difference.
A suspicion i have is that the file descriptor server-side is passed incorectly to the thread,but i can't figure out how. Another suspicion i have is that i am missing something stupidly obvious.
Either way, help is appreciated.
Any ideas?
Server-side: the loop that creates threads.
while (1) {
int client;
printf("[server]Waiting at port %d...\n", PORT);
fflush(stdout);
int length = sizeof(from);
if (client = accept(sd, (struct sockaddr*)&from, &length) < 0) {
perror("[server]Error: accept().");
continue;
}
pthread_t th_id;
pthread_create(&th_id, NULL, &treat, &client);
}
Server-side: thread's treat function (the problem is here).
void* treat(void* client)
{
printf("[thread]Waiting for message...\n");
fflush(stdout);
pthread_detach(pthread_self());
int client_sd = *((int*)client);
int nr;
if (read(client_sd, &nr, sizeof(int))) {
perror("[thread]Error: read().");
exit(-1);
}
// The program won't reach this point.
printf("[thread]Read: %d", nr);
fflush(stdout);
close(*((int*)client));
return (NULL);
}
Client-side:
if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1)
{
perror ("[client]Error: connect().\n");
return errno;
}
printf ("[client]Write a number: ");
fflush (stdout);
scanf("%d",&nr);
printf("[client] Read %d\n",nr);
if (write (sd,&nr,sizeof(int)) <= 0)
{
perror ("[client]Error: write()\n");
return errno;
}
//the program reaches here.
printf("[client]The message was sent\n");
The problem is at line
if (client = accept(sd, (struct sockaddr*)&from, &length) < 0) {
it is interpreted as
if (client = (accept(sd, (struct sockaddr*)&from, &length) < 0)) {
and if accept returns positive then the client is set to 0. Subsequent read in the thread is read from stdin then.
I have a tcp echo server that creates a pthread for each client that connects to it. For each connection, I have a variable nbOfClients that increments.
When a client closes its connection, I detect it and decrease the number of clients. However the server keeps thinking that the client it alive and keeps on trying to read/write from the socket. I guessed that it was because of the thread that created the client and I tries to kill the thread with pthread_cancel all to non avail.
I want to kill the pthread associated to a certain client that closes its connection.
How can I go about it?
Here's my code :
static int nbOfClients = 0;
static pthread_t tid;
int main (int argc, char *argv[]) {
int bytes_to_read, arg, listen_sd, new_conn, sockfd, client_len, port;
struct sockaddr_in server, client_addr;
char *bp, buf[BUFLEN];
ssize_t n;
sockfd = 0;
switch(argc) {
case 1:
port = SERVER_TCP_PORT; // Use the default port
break;
case 2:
port = atoi(argv[1]); // Get user specified port
break;
default:
fprintf(stderr, "Usage: %s [port]\n", argv[0]);
exit(1);
}
// Create a stream socket
if ((listen_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
error("Cannot Create Socket!");
// set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
arg = 1;
if (setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
error("setsockopt");
// Bind an address to the socket
bzero((char *)&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY); // Accept connections from any client
if (bind(listen_sd, (struct sockaddr *)&server, sizeof(server)) == -1)
error("bind error");
listen(listen_sd, MAX_CONNECTIONS); ///put a define constant indicating the maximum number of clients #define NB_CLIENTS 3
while (TRUE) {
client_len = sizeof(client_addr);
if ((new_conn = accept(listen_sd, (struct sockaddr *) &client_addr, (socklen_t *)&client_len)) == -1)
error("accept error");
if(new_conn > 0) {
if(nbOfClients < MAX_CONNECTIONS) {
printf("just here\n");
printf(">> Initializing remote address: %s\n", inet_ntoa(client_addr.sin_addr));
nbOfClients++;
fclose(fp);
printf("Connections to date: %u \n",nbOfClients);
printf("make thread\n");
pthread_create(&tid,NULL,&echo, (void *)new_conn);
printf("had thread\n");
}
else {
printf("connection limit reached\n");
if(send(new_conn, "Server full!\n", 13, 0) == -1)
perror("send");
close(new_conn);
}
}
}
return(0);
}
void * echo(void *arg) {
char buf[BUFSIZE]; /* message buffer */
int n, i = 0;
bzero(buf, BUFSIZE);
if(send((int)arg, "Welcome!!\n", 20, 0) == -1)
perror("send");
detect_closed_connection(arg);
while(TRUE) {
n = read((int)arg, buf, BUFSIZE);
/**read: read input string from the client*/
if(n < 0) {
perror("error reading from socket");
}
printf("Server received from client, %d bytes: %s\n", n, buf);
/**write: echo the input string in UPPERCASE back to the client*/
int len = strlen(buf);
for(i = 0; buf[i]; i++)
buf[i] = toupper(buf[i]);
n = write((int)arg, buf, len);
if(n < 0) {
error("ERROR writing to socket");
}
}
}
void detect_closed_connection(void * listenSocket) {
struct pollfd pfd;
pfd.fd = (int)listenSocket;
pfd.events = POLLIN | POLLHUP | POLLRDNORM;
pfd.revents = 0;
while(pfd.revents == 0) {
if(poll(&pfd, 1, 100) > 0) {
// if result > 0, this means that there is either data available on the
// socket, or the socket has been closed
char buffer[32];
if (recv((int)listenSocket, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
// if recv returns zero, that means the connection has been closed:
nbOfClients--;
pthread_cancel(tid);
}
}
}
}
Thanks.
You should check read() for returning 0 in the thread servering the client, as read() returns 0 in case the peer (client here) closed the connection.
After this line
n = read((int)arg, buf, BUFSIZE);
add
if (0 == n)
{
fprintf(stderr, "The client closed the connection.\n");
break;
}
Just before the thread function leave you could add the statement to decrement the number of running threads.
Also be aware that nbOfClients is accessed concurently by all the "client"-threads as well as by the main thread, so accessing it shall be protected, for example by using a mutex.
There is another issues, as the call to strlen() on the buffer read expects the buffer to be 0-terminate, which does not necessarily needs ot be the case, even if you sent 0-terminated "strings". read() might very well return the "string" the client sent in more then one part. So loop around read() until the 0-terminator had been received.
Do not make the thread end itself by calling pthread_cancel(), use pthread_exit() instead.
I'm trying to figure out what is blocking my program. I'm running a server that uses POSIX threads. I have to for my computer programming lab. The main function listens for new connections. Once it accepts a connection, it creates a new thread by passing the FD to the thread. I'm able to successfully connect to the server using multiple telnet/client connections. I can send data to the server successfully once, but if I try sending again the server won't do anything.
Part of the main function
int active_thread = 0;
//The Running loop
while(running)
{
if(active_thread > NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up");
running = false;
}
else
{
if(FD_ISSET(sockfd, &readfds))
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
//close(bindfd[active_thread]);
//pthread_join( threads[active_thread], NULL);
active_thread++;
//running = false;
}
}
}
close(sockfd);
return 0;
}
Part of the POSIX THREAD CODE
void *server_handler( void *sockfd)
{
int bindfd = *( (int *) sockfd);
char buffer[MESSAGELENGTH];
bool running = true;
printf("Thread was created successfully\n");
char intro[] = "Successfully Connected to server!\n";
struct pollfd pfd;
pfd.fd = bindfd;
pfd.events = POLLIN;
if ( (send(bindfd, intro, strlen(intro), 0)) < 0)
{
perror("Unable to send");
}
while(running){
char msg[] = "\nYou have the following options!\n1) Insert an integer: insert <integer>\n2) Remove An Integer: remove <integer>\n3) Get number of integers in list: get_count\n4) Get first integer: get_first\n5) Get last integer: get_last\n6) Quit program: quit\n ";
if ( (send(bindfd, msg, strlen(msg), 0)) < 0)
{
perror("Unable to send");
}
memset(&buffer, 0, MESSAGELENGTH);
if (recv(bindfd, buffer, MESSAGELENGTH, 0) > 0)
{
//SOme other code
}
}
I think its blocking at either the accept or recv. I've heard of select() and various other methods, but I'm having difficulty trying to implement them. Thanks!
The root cause of your issue appears to be that you are unconditionally executing close(sockfd); return 0; at the bottom of your while (running) loop, which means that the loop only ever executes once.
Additionally, you should not be using FD_ISSET() unless you are also using select(). Your main loop should look something more like:
int active_thread = 0;
while (active_thread < NUMBTHREADS)
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
active_thread++;
}
if (active_thread >= NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up.\n");
}
running = false;
close(sockfd);
return 0;
By default network sockets are blocking. You need to set the O_NONBLOCK flag on the socket.
if(fcntl(fd, F_GETFL, &flags) < 0 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
perror("Failed to set socket as non-blocking");
Now, instead of blocking when there is no input (or buffer space to store output), the error EAGAIN (or EWOUDLBLOCK) is returned. Lastly, you will need to use select() or poll() when you have nothing else to do but wait on I/O. These calls will only wake the process when either there is input, room for output, or possibly a time-out period passes.
int maxFd;
fdset fds;
FD_ZERO(&fds);
FD_SET(listenFd, &fds);
FD_SET(sockFd1, &fds);
FD_SET(sockFd2, &fds);
maxFd = listenFd+1;
maxFd = sockFd1 > maxFd ? sockFd1+1 : maxFd;
maxFd = sockFd2 > maxFd ? sockFd2+1 : maxFd;
if(select(maxFd, &fds, &fds, &fds, NULL) < 0) {
perror("Failed on select()");
exit(1);
}
if(FD_ISSET(listenFd, &fds))
...
This example is not complete or neccessarily 100% correct, but should be a good start. Also, I tend to reserve using send*() and recv*() when dealing with SOCK_DGRAM sockets and just use read(), write() on SOCK_STREAM sockets.