2

I'm programing a small c linux local server. I've read a lot of documentation about threads, select function, nonblocking options, etc. But I can't find any documentation about how to deal with client-side failures.

More specifically, working with threads and blocking sockets (not the best idea, I know, but I'm just running some tests), what happens when the client connection goes too slow? or what happens when the client doesn't close the connection properly (or not closing it at all)? Will my socket remain blocked? or the thread will never finish?

How to deal with this situations?

algolejos
  • 129
  • 6
  • each client need to be handle in different thread... if you try to handle all of them they will block each other,if the client close the connection the server will wait until timeout and close the connection...... – Proxytype Jun 27 '15 at 22:39
  • 1
    Look up `EINTR` in `read(2)`/`write(2)`, and `pthread_kill(3)` for how to interrupt a blocking syscall. Note that this means you must *not* pass `SA_RESTART` to `sigaction(2)`, which makes life difficult in general (`select` and family are never auto-restarted). See `signal(7)` for more info. – o11c Jun 27 '15 at 23:00

2 Answers2

2

When using blocking sockets you have a couple of options.

One is to have one thread per client such that when you wait for information it doesn't matter how long you block. Note that when a connection is closed, the blocked operation will terminate. You can read a much more detailed description of this here.

An alternative to multiple threads is to use select. This allows you to wait on multiple file descriptors until some subset of the file descriptors are ready in the sense that they will not block. So basically instead of blocking on a single file descriptor during a read or write, you instead block on select and then you know you won't later block on the read/write.

Finally, you can use the asynchronous I/O functions, aio_read and aio_write which will perform the read/write asynchronously from the calling thread of execution.

Community
  • 1
  • 1
missimer
  • 4,022
  • 1
  • 19
  • 33
  • NB that *"On Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has the wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block."* – Harith Jan 29 '23 at 12:34
1

Typically, sockets have some timeout value which can be controlled by the client. If a connection runs too slowly, or the connection dies for some reason (e.g. poor internet connectivity), the socket operation might continue to block until the timeout expires. With Linux sockets, when the timeout expires, you'll get an ETIMEDOUT errno that you can then handle later.

Typical values for the timeout are on the order of 60-300 seconds, but you can set them lower if you want to know about timeouts sooner. You can also set it to infinite, but this isn't recommended if you're using direct blocking calls since you could hang your thread forever.

On Linux (and any other system using the BSD socket API), you may change the socket timeouts using

struct timeval timeout;
timeout.tv_sec = 60;
timeout.tv_usec = 0;

setsockopt(socket, SOL_SOCK, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
algolejos
  • 129
  • 6
nneonneo
  • 171,345
  • 36
  • 312
  • 383