[Sockets] Select für mehr als 64 Sockets
-
Hallo
ich möchte, wie der Titel schon sagt, Select auf mehrere Sockets anwenden.
Da der Code unter Realbedingungen schwer zu testen ist, wollte ich einfach nur
mal ein kurzes Feedback ob das so richtig ist vom Prinzip her.fd_set *bigset = reinterpret_cast<fd_set *>(new char[sizeof(u_int) + sizeof(SOCKET) * numsockets]); FD_ZERO(bigset); #ifdef FD_SETSIZE #undef FD_SETSIZE #endif #define FD_SETSIZE numsockets for (unsigned i = 0; i < numsockets; ++i) FD_SET(sockets[i], bigset); timeval tv; tv.tv_usec = (milliseconds % 1000) * 1000; tv.tv_sec = milliseconds / 1000; select(0, bigset, 0, 0, &tv); // aufräumcode gekürzt
ob das standartkonform ist, ist mir egal es muss nur unter windows xp
laufen
-
eher andersrum
du darfst definieren und die winsock2.h macht#ifndef FD_SETSIZE #define FD_SETSIZE 64 #endif
du mußt das als definieren, bevor du die winsock2.h inkludierst oder irgendeine *.h, die sie inkludiert.
-
@volkard:
Was ich weiss muss man nur die Struktur richtig zusammenbauen.
Also dass als erstes ein u_int mit N kommt, und dann halt die SOCKETs.@steckverbindung:
Bei x64 wird's deinen Code vermutlich aufstellen, weil du das Structure-Alignment/Padding nicht berücksichtigst.
u_int ist auf x64 AFAIK weiterhin 4 Byte, aber SOCKET (UINT_PTR) ist 8 Byte. Default Packing vom VS is 8, d.h. VS wird zwischen dem u_int und dem SOCKET Array 4 Byte Padding reinknallen (damit das Array bei Offset 8 anfängt).Die ganz einfache Variante wäre IMO sowas in der Art:
std::vector<SOCKET> my_fd_set; // evtl.: my_fd_set.reserve(...); my_fd_set.push_back(0); // erstmal dummy für fd_count // SOCKETs reinstecken for (...) my_fd_set.push_back(...); my_fd_set[0] = my_fd_set.size() - 1; // fixup fd_count timeval tv; tv.tv_usec = (milliseconds % 1000) * 1000; tv.tv_sec = milliseconds / 1000; int rc = select(0, reinterpret_cast<fd_set*>(&(my_fd_set[0]), 0, 0, &tv);
Das sollte mit x86 und x64 funktionieren, und ist IMO etwas schöner.
Oder man kapselt gleich die ganzen hässlichen Details in einer Klasse weg:
class big_fd_set { public: static size_t const npos = ~size_t(0); explicit big_fd_set(size_t reservation = 500) { m_vec.reserve(reservation + 1); m_vec.push_back(0); // dummy fd_count } void clear() { m_vec.clear(); m_vec.push_back(0); // dummy fd_count } size_t count() const { assert(m_vec.size() >= 1); return m_vec.size() - 1; } size_t index_of(SOCKET s) const { std::vector<SOCKET>::iterator const it = find_it(s); if (it != m_vec.end()) return std::distance(m_vec.begin() + 1, it); else return npos; } bool contains(SOCKET s) const { return index_of(s) != npos; } bool add(SOCKET s) { if (!contains(s)) { m_vec.push_back(s); return true; } else return false; } bool remove(SOCKET s) { std::vector<SOCKET>::iterator const it = find_it(s); if (it != m_vec.end()) { m_vec.erase(it); return true; } else return false; } fd_set* get_fd_set() { assert(m_vec.size() >= 1); m_vec[0] = m_vec.size() - 1; // fix-up fd_count return reinterpret_cast<fd_set*>(&(m_vec[0])); } operator fd_set* () { return get_fd_set(); } private: std::vector<SOCKET>::iterator find_it(SOCKET s) const { assert(m_vec.size() >= 1); return std::find(m_vec.begin() + 1 /* skip fd_count */, m_vec.end(), s); } std::vector<SOCKET> mutable m_vec; };
(ungetestet, aber müsste IMO funktionieren)
-
ich dachte mir, dass ich die winsock includiere und die FD_SETSIZE auf 64 setzt.
dann wird meine funktion kompiliert, setz FD_SETSIZE auf numsockets, was zur
folge hat, dass die makros FD_irgentwas mit "numsockets" arbeiten.vielen dank für diese klasse, ich denke das kann ich so übernehmen
@allgemeinheit
wenn ich aus code in eine 32-bit DLL erzeuge, wird die auf einem 64-bit OS
gegen eine 32 oder 64 bit wsock.dll gelinkt? (zur laufzeit)da gibts doch bestimmt einen kompatiblitätsmodus für 32 bit?