[LINUX] fd_set von select (2) fällt ab, wenn versucht wird, fd von 1024 oder mehr einzustellen

Einführung

Abhängig von der Beschreibung im Netz wird häufig geschrieben, dass select nur bis zu 1024 FDs überwachen kann, da das Argument fd_set nur 1024 fds akzeptiert, in Wirklichkeit jedoch ** 1024 oder mehr. fd wird nicht akzeptiert **. Selbst wenn es einer ist, wird er gelöscht, wenn Sie versuchen, eine Zahl von 1024 oder mehr FD_SET zu setzen. Das ist alles für den Abschluss, aber ich möchte den Inhalten folgen.

Wenn Sie genau hinschauen, finden Sie es auch in Manpage auswählen.

fd_set ist ein Puffer mit fester Größe. Es ist nicht definiert, was passiert, wenn FD_CLR () oder FD_SET () auf einem fd ausgeführt wird, der negativ ist oder einen Wert größer oder gleich FD_SETSIZE hat.

Es gibt eine undefinierte Handlungserklärung der Angst.

select(2) Ein Systemaufruf, der Dateideskriptoren und Socket-Deskriptoren überwacht und normalerweise nicht weiß, wann ein eingehender Anruf eintrifft, z. B. ein Serverprogramm, ist ein häufig verwendeter Systemaufruf, um auf einen eingehenden Anruf zu warten.

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

Abgesehen von den Details handelt es sich grob gesagt um einen Systemaufruf, der den in fd_set registrierten fd (Dateideskriptor) überwacht. Durch Verknüpfen von Auswahl (2) mit Lesen (2) können Daten effizienter und ereignisgesteuert gelesen werden, als wenn das Lesen beschäftigt ist. Es ist wie der Urheber von boost :: asio :: async_read.

fd_set und FD_SET

Wie der Name schon sagt, ist fd_set eine Struktur, die eine Menge von fd darstellt. Blick auf mein sys / select.h (ganz weggelassen)

typedef long int __fd_mask;
# define __FD_SETSIZE 1024
# define __NFDBITS (8 * (int)sizeof(__fd_mask));

typedef struct
  {
    __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
  } fd_set;

Wenn Sie es lesen, wenn es sich um eine 64-Bit-Version von Linux handelt, ist long also 64-Bit

typedef struct {
    long int fds_bits[16];
} fd_set;

Daher wird es am Ende eine Struktur mit einer Fläche von 1024 Bit (64 Bit * 16). Und es ist das FD_SET Makro, das den hier enthaltenen fd festlegt.

#define	__FD_ELT(d) ((d) / __NFDBITS)
#define	__FD_MASK(d) ((__fd_mask) (1UL << ((d) % __NFDBITS)))
#define __FD_SET(d, set) ((void) (__FDS_BITS (set)[__FD_ELT (d)] |= __FD_MASK (d)))
#define	FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp)

Es ist ein wenig schwer zu verstehen. Wenn Sie also das Makro lösen,

fdsetp->fds_bits[fd/64] |= (__fd_mask) (1UL << (fd % 64));

Kurz gesagt, es wird verarbeitet, um das Bit der fd-Ziffer von fdsetp (Zeiger der Variablen vom Typ fd_set) zu setzen.

Verstehst du?

Korrekt. In dem Moment, in dem fd 1024 überschreitet, fällt es aufgrund eines Pufferüberlaufs ab. Darüber hinaus ist FD_SETSIZE mit define fest codiert und kann nicht geändert werden, da es beängstigend ist. redhat QA page gibt außerdem an, dass FD_SETSIZE nicht neu geschrieben werden sollte. Die Obergrenze von "ulimit" liegt oft bei 1024, selbst in modernen Hauptdistributionen, aber ich denke, dass es für Serverprogrammschreiber eine natürliche Einstellung ist, die Obergrenze mit ulimit zu entfernen. Insbesondere wenn Sie Docker verwenden, können Sie die Einschränkung optional problemlos entfernen. Wenn die Bibliothek, die Sie in Ihrem Programm verwenden, jedoch mit "select (2)" implementiert ist, fällt sie unerwartet ab!

Zusammenfassung

Wenn Sie einen Deskriptor verwenden, um das "ulimit" -Limit in einem Programm zu entfernen, das select (2) verwendet, schlägt dies mit "FD_SET" fehl. Tatsächlich stieß ich beim Schreiben eines Programms mit einer Bibliothek eines bestimmten NW-Protokolls auf dieses Problem. Von nun an sollten diejenigen, die Low-Layer-NW-Programme schreiben, die Verwendung von "select (2)" vermeiden. Bitte benutze poll (2)!

Recommended Posts

fd_set von select (2) fällt ab, wenn versucht wird, fd von 1024 oder mehr einzustellen
Fehler beim Versuch, psycopg2 in Python zu installieren
UnicodeEncodeError beim Versuch, Radon auszuführen