2010-03-11 4 views
1

Je m'écris moi-même un démon de petit serveur en C, et les parties de base comme le traitement se connecte, se déconnecte et reçoit sont déjà présentes, mais un problème de réception persiste. J'utilise "recv" pour lire 256 octets à la fois dans un tableau char, et comme il peut contenir plusieurs lignes de données en un seul gros morceau, je dois pouvoir séparer chaque ligne séparément pour le traiter. Cela ne serait pas le seul problème, mais à cause de la possibilité qu'une ligne puisse être coupée parce qu'elle ne rentrait plus dans le tampon, je dois aussi pouvoir voir si une ligne a été coupée. Pas si mal, aussi, juste vérifier le dernier caractère pour \r ou \n, mais ce si la ligne a été coupée? Mon code ne permet pas de "lire simplement plus de données" car j'utilise select() pour gérer plusieurs requêtes.Séparer de manière fiable les lignes d'une chaîne

En gros, voici ma situation:

//This is the chunk of code ran after select(), when a socket 
//has readable data 
char buf[256] = { 0 }; 
int nbytes; 

if ((nbytes = recv(i, buf, sizeof(buf) - 1, 0)) <= 0) 
{ 
    if (nbytes == 0) 
    { 
     struct remote_address addr; 

     get_peername(i, &addr); 
     do_log("[Socket #%d] %s:%d disconnected", i, addr.ip, addr.port); 
    } 
    else 
     do_log("recv(): %s", strerror(errno)); 

    close(i); 
    FD_CLR(i, &clients); 
} 
else 
{ 
    buf[sizeof(buf) - 1] = 0; 
    struct remote_address addr; 

    get_peername(i, &addr); 
    do_log("[Socket #%d] %s:%d (%d bytes): %s", i, addr.ip, addr.port, nbytes, buf); 

    // split "buf" here, and process each line 
    // but how to be able to get the rest of a possibly cut off line 
    // in case it did not fit into the 256 byte buffer? 
} 

Je pensais avoir un pour sauver le tampon courant dans, si elle était trop longue variable tampon temporaire plus SCOPED (éventuellement malloc() « d) pour tenir dans à la fois, mais je me sens toujours mal d'introduire des variables de portée inutilement élevé s'il y a une meilleure solution:/

J'apprécie tous les pointeurs (à l'exception des XKCD :))!

+2

void * ptr = &ptr; // Voici un pointeur – Tronic

+0

qui tombe sous la rubrique « les xkcd »: http://xkcd.com/138/ – LukeN

Répondre

3

Je suppose que vous devez ajouter un autre tampon par flux qui contient la ligne incomplète jusqu'à ce que le saut de ligne qui suit soit reçu.

+0

En effet, si vous ajoutez le traitement des backspace, vous pourriez faire ur travail avec application HyperTerminal trop puisque l'utilisateur est autorisé à annuler leur faute de frappe – YeenFei

+0

Ceci est la façon standard de faire les choses (vous pouvez faire le 'read' directement dans ce tampon par-flux). – caf

0

J'utiliserais un type de tampon à expansion dynamique tel que GString pour accumuler des données.

L'autre chose qui pourrait aider serait mettre le socket en mode non-bloquant en utilisant fcntl(). Ensuite, vous pouvez recv() dans une boucle jusqu'à ce que vous obteniez un -1. Vérifiez errno, ce sera soit EAGAIN ou EWOULDBLOCK (et ceux-ci ne sont pas tenus d'avoir la même valeur: vérifiez les deux).

Remarque finale: J'ai trouvé que l'utilisation de libev (google, je ne peux pas poster plusieurs liens) était plus amusant que d'utiliser select().

Questions connexes