Toon posts:

[c++] socket probleem

Pagina: 1
Acties:

Verwijderd

Topicstarter
De volgende code probeert te binden met een bepaalde poort (dit gebruiken we voor onze server).
Nu is het uiteraard de bedoeling dat de server enkel aan een socket bind als daar nog niet aan gebind is,
Vreemd genoeg gaat hij ook binden als er al een proces gebind heeft aan die port.
Iemand enig idee wat er mis is met deze code.

C++:
1
2
3
4
5
6
7
8
9
10
11
bool Socket::Bind(int  & port) {
   if (!Is_valid())
      return false;
   m_addr.sin_family = AF_INET;
   m_addr.sin_addr.s_addr = INADDR_ANY;
   m_addr.sin_port = htons(port);
   int bind_return = bind(m_sock, (struct sockaddr *) &m_addr, sizeof(m_addr));
   if (bind_return == -1)
      return false;
   return true;
}

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Je gebruikt een 'partially wildcard address' oftewel INADDR_ANY. Op dat moment gaat het pas fout zodra je hierna listen aanroeptop de bound socket.

Professionele website nodig?


Verwijderd

Topicstarter
En als ik wil dat het in die bind methode foutgaat, welke parameter moet ik dan meegeven?

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 17:14
De interface waarop je wil luisteren

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • igmar
  • Registratie: April 2000
  • Laatst online: 29-06 18:56

igmar

ISO20022

curry684 schreef op 14 October 2003 @ 14:30:
Je gebruikt een 'partially wildcard address' oftewel INADDR_ANY. Op dat moment gaat het pas fout zodra je hierna listen aanroeptop de bound socket.
De manual zegt niet dat het altijd mis gaat, maar soms.

bind() geeft wel degelijk EADDRINUSE, het volgende stukje code demonstreerd dit :

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char **argv)
{
    int sock;
    struct sockaddr_in server;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("socket");
        _exit(0);
    }

    memset(&server, 0, sizeof(server));

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(22);

    if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1) {        perror("bind");
        _exit(0);
    }

    if (listen(sock, 5) == -1) {
        perror("listen");
    }
    for (;;)
        sleep(1);
}


Zorgen dat je SSH hebt draaien, en dat je root bent :

code:
1
2
[root@ouzo igmar]# ./xy 
bind: Address already in use

[ Voor 11% gewijzigd door igmar op 14-10-2003 21:47 . Reden: Taalgebruik ]


  • igmar
  • Registratie: April 2000
  • Laatst online: 29-06 18:56

igmar

ISO20022

Verwijderd schreef op 14 October 2003 @ 14:14:
C++:
1
2
3
4
5
6
7
8
9
10
11
bool Socket::Bind(int  & port) {
   if (!Is_valid())
      return false;
   m_addr.sin_family = AF_INET;
   m_addr.sin_addr.s_addr = INADDR_ANY;
   m_addr.sin_port = htons(port);
   int bind_return = bind(m_sock, (struct sockaddr *) &m_addr, sizeof(m_addr));
   if (bind_return == -1)
      return false;
   return true;
}
Geef geen references door, maar gewoon een plain int :

Bind(int port)
{
}

De rest van de code is zo te zien OK, dus het waarschijnlijk bevat port wat random waarde en gaat het daarom mis.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

igmar schreef op 14 October 2003 @ 20:59:
[...]
Wat een gelul zeg. En is geen 'partially wildcard address'. INADDR_ANY is gewoon 0.0.0.0, en da's alle addressen. Niet meer, niet minder.
Een geheel wildcard address is ook een partially wildcard address :z
bind() geeft wel degelijk EADDRINUSE, het volgende stukje code demonstreerd dit :
Helaas gebruik jij Linux, waar dat blijkbaar door Berkeley sockets gegarandeerd wordt. Blijkbaar gebruikt TS WinSock, want de tekst over dat bind(...) niet altijd op tijd z'n error klaar heeft waardoor ie pas bij listen(...) naar buiten komt heb ik letterlijk vanaf MSDN vertaald.

http://msdn.microsoft.com...sock/winsock/listen_2.asp
WSAEADDRINUSE: The socket's local address is already in use and the socket was not marked to allow address reuse with SO_REUSEADDR. This error usually occurs during execution of the bind function, but could be delayed until this function if the bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be committed at the time of this function.

Professionele website nodig?


  • igmar
  • Registratie: April 2000
  • Laatst online: 29-06 18:56

igmar

ISO20022

curry684 schreef op 14 October 2003 @ 21:11:
Helaas gebruik jij Linux, waar dat blijkbaar door Berkeley sockets gegarandeerd wordt. Blijkbaar gebruikt TS WinSock, want de tekst over dat bind(...) niet altijd op tijd z'n error klaar heeft waardoor ie pas bij listen(...) naar buiten komt heb ik letterlijk vanaf MSDN vertaald.
Ik lees dat als een obscure race die wel eens voorkomt. Niet altijd. In het geval van de poster gaat de bind() altijd goed, dus is d'r wat anders aan de hand.

Ik heb ondanks de vele Windows ports van daemons nog nooit meegemaakt dat de listen() pas de ADDRINUSE teruggeeft.
Een printf() voor het vullen van de poort zou simpel moeten vertellen op welke poort de bind plaatsvind, anders kan de debugger van MSVC je dat vertellen.

Verwijderd

Topicstarter
ik heb nu al geprobeerd om een gewone int mee te geven maar zonder resultaat

ik weet dat er altijd gebind gaat worden op poort 3000, aangezien dit de eerste is waarmee hij probeert te binden

als het probleem zou liggen aan m_addr.sin_addr.s_addr = INADDR_ANY op welke waarde moet ik m_addr.sin_addr.s_addr dan zetten om dit probleem niet te hebben?

  • rig0r
  • Registratie: Juli 2001
  • Laatst online: 11-03-2025
Waar is die &port goed voor ?

Deze code werkt : (op linux en windows)

C++:
1
2
3
4
5
6
7
8
9
10
...
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr  = INADDR_ANY;
  addr.sin_port = htons( port );

  if ( bind( sockfd_, (sockaddr *) &addr, sizeof( addr ) ) != 0 ) {
    disconnect();
    throw ESocket( "Unable to bind to address", ERRNO );
  }
...


en gooit netjes een exception als de poort in use is. Voorwaarde op windows platforms is dat je de socket optie SO_REUSEADDR <niet> aanzet, omdat je dan het gedrag krijgt wat je in je TS noemt. Op linux platforms werkt deze optie wel gewoon naar behoren.

[ Voor 3% gewijzigd door rig0r op 05-11-2003 20:42 ]


Verwijderd

Topicstarter
idd
bij setsockopt geef ik SO_REUSEADDR mee
ik heb nu SO_EXCLUSIVEADDRUSE meegegeven id plaats van SO_REUSEADDR maar dit kan de compiler niet vinden,
enig idee welke waarde ik dan wel moet meegeven aan deze optie?
Pagina: 1