简体   繁体   中英

Can we make a non-blocking server with blocking sockets?

I have to make a simple IRC client/server programs for my IT school. The subject asks us to use select(2) for socket polling but forbids us to use O_NONBLOCK sockets.

  • Your server will accept multiple simultaneous connections.
    Attention, the use of fork is prohibited. So you should imperatively use select
  • Your server must not be blocking.
    This has nothing to do with non-blocking sockets, which are prohibited (so do not use fcntl(s, O_NONBLOCK) )

I'm wondering if it is even possible to design a non-blocking server (which does not fork) with blocking sockets even using select(2) .

Here is a simple example: let say we have a simple text protocol with one command per line. Each client has a buffer. When select(2) tells us a client is ready for read(2) , we read until we found a \\n in the client buffer, therefor we process the command. With non-blocking sockets, we would read until EAGAIN .

Let imagine now that we are using blocking sockets and a malicious client sends text with no line-break. select(2) tells us data is available, we then read(2) on the client. But we will never read the expected \\n . Instead of returning EAGAIN , the syscall will block indefinitely. This is a denial of service attack.

Is it really possible to design a non-blocking server with blocking-sockets and select(2) (no fork(2) )?

Yes, you read once from the socket that select tells you is ready. If the read contains the \\n , then process that line. Otherwise, store any data that was received, and immediately go back to the select .

This means of course, that for every open socket, you must maintain state information, and a buffer of data read so far. This allows the code to process each read independently, without the need to finish a full line before going back to the select .

It's impossible.

  1. select() blocks, and therefore so does any program that calls it.
  2. The behaviour defined by Posix for send() in blocking mode is that it blocks until all the data supplied has been transferred to the socket send buffer. Unless you're going to delve into low-water marks and so on, it is impossible to know in advance whether there is enough room in he socket send buffer for any given send() to complete without blocking, and therefore impossible for any program that calls send() not to block.

    Note that select() doesn't help you with this. It can tell when you when there is some room, but not when there is enough.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM