2 Stimmen

Socket-Programmierung in C unter Verwendung der Funktion select()

Ausgehend von den Antworten, die ich von dieses Thema habe ich dies erstellt:

    //Server 

    sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/

    timeout = 50000;

    serv_sock_input[0] = TCP(1234); 
    serv_sock_input[1] = UDP(9876);

    input_protocols[0] = "tcp";
    input_protocols[1] = "udp";

    while (1)
    {
        FD_ZERO(&sock_set);
        for (x = 0; x<number_of_inputs; x++)
        {
            FD_SET(serv_sock_input[x], &sock_set);
        }

        select_timeout.tv_sec = timeout;
        select_timeout.tv_usec = 0;

        if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
            printf("No requests");
        else
        {
            for (x = 0; x<number_of_inputs; x++)
            {
                if (FD_ISSET(serv_sock_input[x],&sock_set))
                {
                    printf("\nRequest on port %d: \n", x);
                    if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE
                    {
                        accept_socket(serv_sock_input[x]);
                        printf("Input TCP Port %d\n",x);
                        close_socket(serv_sock_input[x]);
                    }
                    else
                    {
                        printf("Input UDP Port %d\n",x);
                    }
                }
            }
        }
    }
    sock_term();
}

int TCP (unsigned short port)
{
    int sock;                        
    struct sockaddr_in servAddr; 

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        exit(1);

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;         
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(port);            

    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
        exit(1);

    if (listen(sock, 5) < 0)
        exit(1);

    return sock;
}

int UDP (unsigned short port)
{
    int sock;                        /* socket to create */
    struct sockaddr_in servAddr; /* Local address */

    /* Create socket for sending/receiving datagrams */
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        exit(1);

    /* Construct local address structure */
    memset(&servAddr, 0, sizeof(servAddr));   /* Zero out structure */
    servAddr.sin_family = AF_INET;                /* Internet address family */
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
    servAddr.sin_port = htons(port);      /* Local port */

    /* Bind to the local address */
    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
        exit(1);

    return sock;
}

//Client
sock_init();

    if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        exit(1);

    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family      = AF_INET;
    client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    client_addr.sin_port        = htons(1234);

    if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0)
        exit(1);

    closesocket(client_sock_output);

    sock_term();

Wenn der Server startet, wird der Server an der if(select(...)) Erklärung.

Wenn ich also den Server und dann den Client ausführe, verbindet sich der Client mit dem Server (manchmal dauert es ein paar Mal, bis der Client eine Verbindung herstellt). Dann wird der if(select...)) Anweisung ist nicht mehr wahr und es wird mit der else-Anweisung fortgefahren.

Danach schließt der Client die Verbindung, und das Programm wird beendet. Allerdings, und das ist der Punkt, an dem mein Problem auftritt, ist die if(select(...)) Aussage ist immer falsch. Ich erhalte diese Ausgabe:

Request on port 0:  
Input TCP Port 0  

Request on port 1:  
Input UDP Port 1

Diese Ausgabe wiederholt sich ständig. Wie kommt es, dass sie nicht bei der if(select(...)) ?

5voto

Sie haben zwei Probleme: Sie verstehen nicht, wie accept() in TCP funktioniert, und Sie müssen die eingehenden Daten in UDP lesen.

select() teilt Ihnen mit, dass ein lauschender Socket eine Verbindung zu akzeptieren hat, oder ein lesender Socket Daten zu lesen hat.

Damit Select aufhört, Ihnen das zu sagen, müssen Sie die Daten tatsächlich lesen oder die Verbindung akzeptieren.

In Ihrem UDP-Zweig müssen Sie receiv aufrufen, um die Daten tatsächlich zu erhalten. Wenn Sie das nicht tun, wird select Ihnen immer wieder sagen, dass Sie Daten haben.

In Ihrem TCP-Zweig rufen Sie accept_socket auf. Ich weiß nicht, wie Ihre Implementierung aussieht, aber es ist höchstwahrscheinlich falsch, den Socket zu schließen, den Sie gerade mit accept() aufgerufen haben. accept() gibt einen neuen Socket für Sie zurück - den, den Sie für IO verwenden sollten. Wenn irgendetwas geschlossen werden muss, dann ist es dieser neue Socket.

1voto

Karthik Kumar Punkte 1295

Bitte prüfen Sie, warum Sie dies im Server haben.

wenn ( select(0, &sock_set, NULL, NULL, &select_timeout) == 0)

ersetzen Sie es durch

wenn ( wählen( maxDescPlus1 , &sock_set, NULL, NULL, &select_timeout) == 0)

wobei maxDescPlus1 --> die Anzahl der auszuwählenden Deskriptoren plus 1 Wert ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X