I have a chat application that has a separate thread to listen for incoming messages.
while (main thread not calling for receiver to quit) {
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
This way of working has one big problem. Most of the time, the loop will be blocking on recv()
so the receiver thread won't quit. What would be a proper way to tackle this issue without forcing thread termination after a couple of seconds?
Close the socket with shutdown()
to close it for all receivers.
This prints out 'recv returned 0' on my system, indicating that the receiver saw an orderly shutdown. Comment out shutdown()
and watch it hang forever.
Longer term, OP should fix the design, either using select
or including an explicit quit message in the protocol.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
/* Free on my system. YMMV */
int port = 7777;
int cd;
void *f(void *arg)
{
/* Hack: proper code would synchronize here */
sleep(1);
/* This works: */
shutdown(cd, SHUT_RDWR);
close(cd);
return 0;
}
int main(void)
{
/* Create a fake server which sends nothing */
int sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa = { 0 };
const int on = 1;
char buf;
pthread_t thread;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(port);
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
/* Other error reporting omitted for clarity */
if (bind(sd, (const struct sockaddr*)&sa, sizeof sa) < 0) {
perror("bind");
return EXIT_FAILURE;
}
/* Create a client */
listen(sd, 1);
cd = socket(AF_INET, SOCK_STREAM, 0);
connect(cd, (const struct sockaddr*)&sa, sizeof sa);
accept(sd, 0, 0);
/* Try to close socket on another thread */
pthread_create(&thread, 0, f, 0);
printf("recv returned %d\n", recv(cd, &buf, 1, 0));
pthread_join(thread, 0);
return 0;
}
You could use select() to wait for incoming data and avoid blocking in recv(). select() will also block, but you can have it time out after a set interval so that the while loop can continue and check for signals to quit from the main thread:
while (main thread not calling for receiver to quit) {
if (tcpCon.hasData(500)) { // Relies on select() to determine that data is
// available; times out after 500 milliseconds
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
}
If you close the socket in another thread, then recv() will exit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With