2012-04-11 15 views
1

Ich habe einen Server-Daemon auf einem TCP-Unix-Domäne/lokalen Socket zuhören. Mehrere Clients, die auf demselben Computer ausgeführt werden, stellen eine Verbindung her. Der Daemon ist auch an einen UDP-Internet-Socket gebunden. Wenn der Daemon Daten von einem der lokalen Clients empfängt, sendet er dieselben Daten an alle verbundenen Clients mit Ausnahme des sendenden Clients. Wenn der Daemon Daten über den UDP-Internet-Socket empfängt, muss er diese Daten an alle lokalen verbundenen Clients senden. Das Senden/Empfangen von Daten funktioniert einwandfrei, wenn der Daemon Daten auf dem lokalen Socket empfängt. Die Clients erhalten jedoch keine Daten, wenn der Server ihnen am UDP-Internet-Socket empfangene Daten sendet. Die Clients empfangen diese Internetdaten entweder nachdem der Serverdämon beendet wurde und die Verbindung geschlossen wurde, oder wenn einer der Clients Daten lokal an den Server sendet. Die Internetdaten werden von den Clients zusammen mit den lokalen Daten empfangen. Ich habe sowohl lokale als auch inet-Sockets als Sperren mit fcntl() festgelegt. Hier ist der Daemon-Code, ich habe (ich alle unnötigen Code entfernt haben):Socket recv() empfängt keine Daten

while(1) 
{ 
    FD_SET(sockfd, &read_fds); 
    FD_SET(inet_sock, &read_fds); 
    for (i = 0; i < nclients; i++) 
    { 
    FD_SET(clients[i], &read_fds); 
    } 

    select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL); 

    /* Check for events on inet sock */ 
    if (FD_ISSET(inet_sock, &read_fds)) 
    { 
    /* Read from inet sock */ 
    socklen = sizeof(dest_sin); 
    rval = recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT, 
        (struct sockaddr *) &dest_sin, &socklen);   
    buf[rval]=0; 
    fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf); 

    /* Send the message to every other client */ 
    for(j=0; j < nclients; j++) 
    { 
     send(clients[j], buf, strlen(buf), MSG_DONTWAIT); 
    } 
    } 

    /* A read event on the local socket is a new connection */ 
    if (FD_ISSET(sockfd, &read_fds)) 
    { 
    socklen = sizeof(dest_sun); 
    /* Accept the new connection */ 
    rval = accept(sockfd, (struct sockaddr *) &dest_sun, &socklen); 

    /* Add client to list of clients */ 
    clients[nclients++] = rval; 
    if (rval > maxfd) maxfd = rval; 
    snprintf(s, BUFLEN, "You are client %d [%d]. You are now connected.\n\0", 
     nclients, rval); 
    send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT); 
    } 

    /* Check for events from each client */ 
    for (i = 0; i < nclients; i++) 
    { 
    fprintf(stderr,"Checking client %d [%d] for read indicator.\n",i, clients[i]); 

    /* Client read events */ 
    if (FD_ISSET(clients[i], &read_fds)) 
    { 
     fprintf(stderr, "Client %d [%d] marked for read.\n", i, clients[i]); 

     /* Read from client */ 
     rval=recv(clients[i], buf, BUFLEN-1, MSG_DONTWAIT); 

     buf[rval]=0; 
     fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf); 

     /* Send the message to every other client */ 
     for(j=0; j < nclients; j++) 
     { 
     /* Skip the sender */ 
     if (j == i) continue; 
     /* Send the message */ 
     send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT); 
     } 
    } 
    } 
} 

Hier ist der Client-Code, die ich habe:

while(1) 
{ 
    FD_SET(fileno(stdin), &read_fds); 
    FD_SET(sockfd, &read_fds); 
    select(fileno(stdin) > sockfd ? fileno(stdin)+1 : sockfd+1, 
&read_fds, &write_fds, &except_fds, NULL); 

    if (FD_ISSET(sockfd, &read_fds)) 
    { 
    /* Read from socket and display to user */ 
    mlen = recv(sockfd, (void *)buf, BUFLEN-1, MSG_DONTWAIT); 
    buf[mlen]=0; 
    printf("Received %d bytes: %s", mlen, buf); 
    } 

    if (FD_ISSET(fileno(stdin), &read_fds)) 
    { 
    fgets(buf, BUFLEN, stdin); 
    fprintf(stderr, "Sent %d octets to server.", 
    send(sockfd, (void *)buf, (size_t) strnlen(buf, BUFLEN), 0)); 
    } 
} 

Ziel ist es, haben die Kunden-Daten empfangen sofort, dass der Daemon sie sendet (die Daten, die der Daemon auf seinem inet-Socket empfängt).

EDIT: Ich habe festgestellt, dass, wenn der Daemon die Daten sendet, die select() auf der Clientseite gibt zurück, dass der Socket lesbar ist, aber recv() blockiert, das ist der Grund, dass ich keine Daten über die Client-Seite. Irgendwelche Vorschläge, wie Sie das beheben können?

+0

Während nichts herausspringt, bitte nicht, nur als eine Form, eine send() innerhalb einer printf() -Anweisung. Du hast auch gesagt, du hast den Code gekürzt. Prüft das aktuelle Arbeitsbeispiel die Rückkehrcodes/errno? – Duck

+0

Ja, das eigentliche Programm überprüft den Fehler. – ddd

+0

Die Sache, die zu mir springt ist, dass Sie nie die Rückgabewerte der 'send' und' recv' Anrufe überprüfen. Wie erstellt man den UDP-Socket, sowohl auf dem Server als auch auf dem Client? –

Antwort

1

Hier ist die send() Anrufe aus dem Code, extrahiert und ausgerichtet:

send(clients[j], buf, strlen(buf),  MSG_DONTWAIT); 
send(rval,  s, strnlen(s, BUFLEN), MSG_DONTWAIT); 
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT); 

ich einige Ungereimtheiten hier zu sehen. Manchmal rufen Sie strlen(), manchmal strnlen(), und manchmal strlen() mit zwei Argumente (ich weiß nicht einmal, was das tun wird).

Das Problem, das Sie sehen, hängt möglicherweise mit der Tatsache zusammen, dass Sie keine Informationen über den Socket senden, der anzeigt, wo die Grenzen zwischen Nachrichten sind. Über einen Stream-Socket werden die Nachrichtengrenzen nicht beibehalten und Sie sollten darauf achten, dass in Ihrem Protokoll entsprechende Framing-Informationen enthalten sind, damit der Empfänger die einzelnen Nachrichten extrahieren kann. Sie können sich nicht auf genau die gleiche Anzahl von Bytes verlassen, die durch einen recv() Anruf kommen, wie es in einem send() Anruf war. Sie erhalten die gleiche Gesamt Anzahl der Bytes in der gleichen Reihenfolge (das ist der Punkt eines Stream-Socket), aber die Nachrichten können konsolidiert oder aufgeteilt werden und Sie haben keine Kontrolle darüber.