2016-04-12 5 views
0

J'ai un problème avec le client-serveur winsock lors de l'envoi des données. J'ai une carte contenant un nom d'utilisateur comme clé primaire, et un vecteur de messages pour chaque utilisateur (stocké dans struct): map<std::string,std::vector<message *> > data;Je ne reçois pas toutes les données du client Winsock

struct message{ 
     static unsigned int last_id; 
     unsigned int id; 
     std::string baa; 
     std::string timestamp; 
    } 

J'ai aussi un sérialiseur afin de l'envoyer au client via Winsock (qui accepte uniquement des tableaux de caractères)

class MessageSerializer 
{ 
public: 
    MessageSerializer(const message& messageStruct) 
    : m_msgRef(messageStruct) 
    , m_msgLength(m_msgRef.msg.length()) 
    , m_timeLength(m_msgRef.timestamp.length()) 
    {} 

    size_t RequiredBufferSize() const 
    { 
     return sizeof(int) + sizeof(size_t)*2 + m_msgLength + m_timeLength; 
    } 

    void Serialize(void* buffer) const 
    { 
     PushNum  (buffer, m_msgRef.id); 
     PushString (buffer, m_msgRef.msg.c_str(), m_msgLength); 
     PushString (buffer, m_msgRef.timestamp.c_str(), m_timeLength); 
    } 
private: 
    const message& m_msgRef; 
    const size_t m_msgLength; 
    const size_t m_timeLength; 

    template<typename INTEGER> 
    void PushNum(void*& buffer, INTEGER num) const 
    { 
     INTEGER* ptr = static_cast<INTEGER*>(buffer); 
     //copying content 
     *ptr = num; 
     //updating the buffer pointer to point the next position to copy 
     buffer = ++ptr; 
    } 
    void PushString(void*& buffer, const char* cstr, size_t length) const 
    { 
     PushNum(buffer, length); 
     //copying string content 
     memcpy(buffer, cstr, length); 
     //updating the buffer pointer to point the next position to copy 
     char* ptr = static_cast<char*>(buffer); 
     ptr += length; 
     buffer = ptr; 
    } 
} 

Et pour mettre en œuvre cette sérialiseur, je fais ce qui suit:

message msg_cpy=*data[recvbuf_usrn].at(0); 
MessageSerializer serializer(msg_cpy); 
char* buffer = new char[serializer.RequiredBufferSize()]; 
serializer.Serialize(buffer); 

le problème vient quand envoyer l'horodatage. Dans msg_cpy j'ai les données correctement stockées (par exemple id = 1, msg = bonjour, timestamp = 2016-04-02 10:40:45), mais lors de l'envoi des données, l'horodatage enregistre seulement les trois premières valeurs, c'est à Par exemple, dans le client, je reçois après désérialisation id = 1, msg = hello, et timestamp = 201 suivi de la corbeille. Je sais que le problème réside dans le serveur, et je déduis qu'il peut être la fonction de sérialisation (la seule autre alternative pourrait être la fonction "envoyer" de Winsock). Mais qu'est-ce qui pourrait être mauvais? Si j'écris un msg = 2016-04-02 10:40:20, je le reçois dans le client.

Toute aide est appréciée

+0

Vous devriez essayer de construire un [mcve]. Le problème pourrait résider dans la manière dont vous utilisez le sérialiseur pour envoyer les données, c'est-à-dire dans le code non affiché (et ma boule de cristal est actuellement inutilisée ...) –

+0

Pour envoyer des données j'envoie le 'buffer' renvoyé par' sérialiser .Serialize (buffer) ', car la fonction Winsock à envoyer ne permet que le tableau de caractères. [link] (https://msdn.microsoft.com/es-es/library/windows/desktop/ms737593 (v = vs.85) .aspx) Dans cette page Web apparaît la fonction d'envoi de Winsock, qui prend 'recvbuf' en tant que données d'entrée, qui, dans mon cas, est le tampon. Mais je pense que le problème réside lors de la sérialisation, où le tampon prend déjà la corbeille dans la partie timestamp. C'est pourquoi je n'ai pas attaché le reste. Si vous pouviez avoir une idée de pourquoi cela arrive, j'apprécierais beaucoup. Merci quand même! @ serge-ballesta – Zarauztarra

+0

Ceci est juste une intuition sauvage puisque vous n'avez pas inclus le code d'envoi/réception: TCP est un protocole orienté flux; un seul 'recv()' peut ne pas renvoyer toutes les données. Vous devez faire une boucle en appelant 'recv()' jusqu'à ce qu'un "message" complet soit reçu. – keithmo

Répondre

1

Le code que vous montriez est correct. L'erreur est le code que vous ne montrez pas.

Avec les 2 classes message et MessageSerializer, j'ai essayé ce test simple:

int main() { 
    message msg = {1, "foo", "2016-04-02 10:40:20" }; 

    MessageSerializer msgSer(msg); 

    size_t sz = msgSer.RequiredBufferSize(); 
    char * buffer = new char[sz]; 
    msgSer.Serialize(static_cast<void *>(buffer)); 
    for (int i=0; i<sz; i++) { 
     std::cout << buffer[i] << " (" << std::hex << static_cast<unsigned int>(buffer[i]) << ") "; 
    } 
    std::cout << std::endl; 
    delete[] buffer; 
    return 0; 
} 

Le résultat est comme prévu

(1) (0) (0) (0) (3) (0) (0) (0) f (66) o (6f) o (6f) (13) (0) (0) (0) 2 (32) 0 (30) 1 (31) 6 (36) - (2d) 0 (30) 4 (34) - (2d) 0 (30) 2 (32) (20) 1 (31) 0 (30) : (3a) 4 (34) 0 (30) : (3a) 2 (32) 0 (30) 
+0

Vous avez raison. Le problème était dans la longueur de tampon que je mettais dans la fonction d'envoi de winsock. Le sérialiseur fonctionnait bien. – Zarauztarra