“Illégale chercher” erreur lors du travail avec la prise des cours d'eau avec des non-vide de lire les tampons

Je suis en train d'écrire une application serveur sur Linux x86_64 à l'aide de <sys/socket.h>.
Après avoir accepté une connexion via accept(), j'utilise fdopen() pour envelopper retrouvée prise dans un FILE* flux.

L'écriture et la lecture, que FILE* stream fonctionne généralement très bien, mais le socket devient unsusable dès que j'écris pour elle, alors qu'elle a un non-vide la mémoire tampon de lecture.

Pour les besoins de la démonstration, j'ai écrit un code qui est à l'écoute pour une connexion, puis lit l'entrée, ligne par ligne, dans une mémoire tampon de lecture à l'aide de fgetc(). Si la ligne est trop longue pour tenir dans la mémoire tampon, ce n'est pas entièrement lu, mais au lieu de lire au cours de la prochaine itération.

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
FILE* listen_on_port(unsigned short port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock, (struct sockaddr*) &name, sizeof(name)) < 0)
perror("bind failed");
listen(sock, 5);
int newsock = accept(sock, 0, 0);
return fdopen(newsock, "r+");
}
int main(int argc, char** argv) {
int bufsize = 8;
char buf[9];
buf[8] = 0; //ensure null termination
int data;
int size;
//listen on the port specified in argv[1]
FILE* sock = listen_on_port(atoi(argv[1]));
puts("New connection incoming");
while(1) {
//read a single line
for(size = 0; size < bufsize; size++) {
data = fgetc(sock);
if(data == EOF)
break;
if(data == '\n') {
buf[size] = 0;
break;
}
buf[size] = (char) data;
}
//check if the read failed due to an EOF
if(data == EOF) {
perror("EOF: Connection reset by peer");
break;
} else {
printf("Input line: '%s'\n", buf);
}
//try to write ack
if(fputs("ack\n", sock) == EOF)
perror("sending 'ack' failed"); 
//try to flush
if(fflush(sock) == EOF)
perror("fflush failed");        
}
puts("Connection closed");
}

Le code doit compiler avec gcc sans aucun paramètre. Exécuter avec le numéro de port comme argument et utiliser netcat pour connecter localement.

Maintenant, si vous essayez d'envoyer des chaînes de caractères qui sont plus courtes que 8 caractères, cela fonctionnera parfaitement.
Mais si vous envoyez une chaîne de caractères contenant plus de 10 caractères, le programme échoue.
Cet exemple d'entrée:

ab
cd
abcdefghij

Va créer cette sortie:

New connection incoming
Input line: 'ab'
Input line: 'cd'
Input line: 'abcdefgh'
fflush failed: Illegal seek
EOF: Connection reset by peer: Illegal seek
Connection closed

Comme vous le voyez, (à juste titre) seuls les 8 premiers caractères de abcdefgh sont lus, mais lorsque le programme tente d'envoyer le 'ack' chaîne (que le client ne receves), puis vider le tampon de sortie, nous recevons un Illegal seek d'erreur, et le prochain appel à fgetc() retourne EOF.

Si le fflush() partie est commentée, la même erreur se produit encore, mais le

fflush failed: Illegal seek

ligne est manquante à partir de la sortie du serveur.

Si le fputs(ack) partie est commentée, tout semble fonctionner comme prévu, mais un perror() manuellement appelé à partir de gdb rapports toujours un "Illégal rechercher" de l'erreur.

Si les deux fputs(ack) et fflush() sont commentées, tout ne fonctionner comme prévu.

Malheureusement, je n'ai pas été en mesure de trouver une bonne documentation, ni Internet discussions sur ce problème, donc votre aide serait grandement appréciée.

modifier

La solution que j'ai finalement réglé pour pas utilisation fdopen() et FILE*, car il semble y avoir aucun moyen propre de la conversion d'un socket fd dans un FILE* fiable utilisé dans r+ mode.
Au lieu de cela, j'ai travaillé directement sur le socket fd, l'écriture de mon propre code de remplacement pour fputs et fprintf.

Si quelqu'un en a besoin, voici le code.

InformationsquelleAutor mic_e | 2012-04-21