2010-11-29 10 views
0

Suis-je censé lire chaque caractère jusqu'à ce qu'il atteigne le caractère \ n, les joindre tous ensemble et revenir ou y a-t-il un meilleur moyen? Dois-je utiliser std :: string ou char pour cela?Comment lire à partir d'une socket et renvoyer des lignes individuelles?

J'ai essayé les deux exemples suivants mais je dois les lire comme des lignes distinctes

Exemple 1:

std::string sockread() 
{ 
    std::string s; 
    s.resize(DEFAULT_BUFLEN); 
    int result = recv(m_socket, &s[0], DEFAULT_BUFLEN, 0); 

    if (result > 0) { 
     return s; 
    } else if (result == 0) { 
     connected = false; 
    } else { 
     std::cout << "recv failed with error " << WSAGetLastError() << "\n"; 
    } 
    throw std::runtime_error("Socket connection failed!"); 
} 

Exemple 2:

char sockread(void) 

    { 
    int result; 
    char buffer[DEFAULT_BUFLEN]; 
     result = recv(m_socket, buffer, DEFAULT_BUFLEN, 0); 

     if (result > 0) { 
      return *buffer; 
       } 
      else if (result == 0) 
       { 
      connected = false; 
       return *buffer; 
       } 
      else { 
     printf("recv failed with error: %d\n", WSAGetLastError()); 
     return *buffer; 
     } 

    } 

Répondre

0

Vous avez un peu d'options, en fonction de la disposition du reste de votre code de socket.

L'approche la plus simple, du point de vue du codage, consiste à lire 1 caractère à la fois jusqu'à ce que vous rencontriez le caractère que vous recherchez. Ce n'est pas la meilleure approche du point de vue de la performance, mais vous pouvez utiliser un tampon local pour vous aider à éviter de fragmenter la mémoire au moins, par exemple:

std::string sockread(void) 
{ 
    char buffer[DEFAULT_BUFLEN]; 
    int buflen = 0; 
    char c; 
    std::string s; 

    do 
    { 
     int result = recv(m_socket, &c, 1, 0); 
     if (result > 0) 
     { 
      if (c == '\n') 
       break; 

      if (buflen == DEFAULT_BUFLEN) 
      { 
       s += std::string(buffer, buflen); 
       buflen = 0; 
      } 

      buffer[buflen] = c; 
      ++buflen; 

      continue; 
     } 

     if (result == SOCKET_ERROR) 
     { 
      if (WSAGetLastError() == WSAEWOULDBLOCK) 
       continue; 

      std::cout << "recv failed with error " << WSAGetLastError() << "\n"; 
     } 
     else 
      connected = false; 

     throw std::runtime_error("Socket connection failed!"); 
    } 
    while (true); 

    if (buflen > 0) 
     s += std::string(buffer, buflen); 

    return s; 
} 

D'autre part, la lecture des données de socket premières dans un tampon intermédiaire que le reste de votre fonctions de lecture d'accès en cas de besoin permet plus de lecture efficace de la prise afin que les données est obtenue sur les tampons de socket plus rapide (provoquant moins le blocage de l'autre côté), par exemple:

std::vector<unsigned char> buffer; 

std::string sockread(void) 
{ 
    unsigned char buf[DEFAULT_BUFLEN]; 
    int result; 
    std:vector<unsigned char>::iterator it; 

    do 
    { 
     it = std::find(buffer.begin(), buffer.end(), '\n'); 
     if (it != buffer.end()) 
      break; 

     result = recv(m_socket, buf, DEFAULT_BUFLEN, 0); 
     if (result > 0) 
     { 
      std::vector<unsigned char>::size_type pos = buffer.size(); 
      buffer.resize(pos + result); 
      memcpy(&buffer[pos], buf, result); 
      continue; 
     } 

     if (result == SOCKET_ERROR) 
     { 
      if (WSAGetLastError() == WSAEWOULDBLOCK) 
       continue; 

      std::cout << "recv failed with error " << WSAGetLastError() << "\n"; 
     } 
     else 
      connected = false; 

     throw std::runtime_error("Socket connection failed!"); 
    } 
    while (true); 

    std::string s((char*)&buffer[0], std::distance(buffer.begin(), it)); 
    buffer.erase(buffer.begin(), it); 
    return s; 
} 
+0

En utilisant la deuxième méthode, que je reçois cette erreur - erreur C2664: 'recv': ne peut pas convertir le paramètre 2 de 'unsigned char [512]' à 'char *' Types souligné ne sont pas liés; la conversion nécessite reinterpret_cast, cast de style C ou cast de style fonction – thorvald

+0

et si je le change en buf [DEFAULT_BUFLEN] (je ne sais pas si c'est mauvais) alors ça marche mais seulement la première ligne est retournée et le reste sont des chaînes vides. – thorvald

+0

Comme le message d'erreur dit, utilisez un type de cast: 'result = recv (m_socket, (char *) buf, DEFAULT_BUFLEN, 0);' –

0

Utilisez Boost Les opérations basées sur .ASIO ont couvert here.

De nombreux protocoles Internet couramment utilisés sont à base de ligne, ce qui signifie qu'ils ont éléments de protocole qui sont délimitée par la séquence de caractères « \ r \ n ». Les exemples incluent HTTP, SMTP et FTP. Pour permettre plus facilement l'implémentation des protocoles basés sur la ligne , ainsi que d'autres protocoles qui utilisent des délimiteurs, Boost.Asio inclut les fonctions read_until() et async_read_until().

+0

Merci pour la suggestion. Je vais essayer aussi. – thorvald

+0

Il est probable qu'il faudra travailler un peu plus pour maîtriser la bibliothèque, mais moins de travail une fois que vous serez opérationnel, puisque le code de la bibliothèque est stable. –