2012-12-28 292 views
2

我有1臺服務器是用Unix和C++編寫的。客戶端正在使用QT和隨附的套接字API。在套接字之間發送消息

服務器向客戶端發送345字節的數據。從服務器

發送消息:在客戶端

void Moderator::testSynch(){ 
    int type = (int) SYNCRHONIZE_M; 
    //Update all connected clients with info about other clients 
    for(int i = 0; i<nrOfClients_; i++){ 
    const TcpSocket &clientSocket = clients_[i].getSocket(); 
    int clientID = clients_[i].getID(); 

    int tempType = htonl(type); 
    int tempClientID = htonl(clientID); 
    int tempNrOfClients = htonl(funNrOfClients); 

    clientSocket.writeData((const char*) &tempType, sizeof(tempType)); 
    clientSocket.writeData((const char*) &tempClientID, sizeof(tempClientID)); 
    clientSocket.writeData((const char*) &tempNrOfClients, sizeof(tempNrOfClients)); 

    for(int j = 0; j<nrOfClients; j++){ //Send info about connectecd clients 

     int tempLength = (int) clients_[j].getName().length(); 
     int tempID = clients_[j].getID(); 
     string tempName = clients_[j].getName(); 

     tempID = htonl(tempID); 
     tempLength = htonl(tempLength); 
     clientSocket.writeData((const char*) &tempID, sizeof(tempID)); 
     clientSocket.writeData((const char*) &tempLength, sizeof(tempLength)); 
     clientSocket.writeData(tempName.c_str(), (int)tempName.length()); 

    } 
    } 
} 

bool TcpSocket::writeData(const char* buffer, int length)const{ 
    size_t bytesLeft = length; 
    ssize_t bytesWritten = 0; 

    while((bytesWritten = write(socketFD_, buffer, bytesLeft)) > 0){ 
    bytesLeft -= bytesWritten; 
    buffer += bytesWritten; 
    } 
    return bytesLeft == 0; 
} 

讀消息:

void ChatClient::readMessage(Message &message){ 

if(socket_->readData((char*) &type, sizeof(type))){ 
    if(type == SYNCRHONIZE_M){ 
     int nrOfUsers = 0; 

     socket_->readData((char*) &ID_, sizeof(ID_)); //Set the client ID that server gave us 
     socket_->readData((char*) &nrOfUsers, sizeof(nrOfUsers)); 

     ID_ = ntohl(ID_); 
     nrOfUsers = ntohl(nrOfUsers); 
     qDebug("%s=%d", "nrOfUsers", nrOfUsers); 
     message.setMessageType(SYNCRHONIZE_M); 
     messageOK = true; 
     for(int i = 0; i<nrOfUsers; i++){ //Update client with all connected users to server 
      int userID = 0; 
      int nameLength = 0; 

      socket_->readData((char*) &userID, sizeof(userID)); 
      socket_->readData((char*) &nameLength, sizeof(nameLength)); 

      userID = ntohl(userID); 
      nameLength = ntohl(nameLength); 

      if(nameLength > 0){ 
       qDebug("%s=%d", "nameLength", nameLength); 
       buffer = new char[nameLength]; 
       socket_->readData(buffer, nameLength); 

       message.addUser(ConnectedUser(buffer, nameLength, userID)); 
       delete [] buffer; 
      } 
     } 
    } 
} 
} 

bool TcpSocket::readData(char* buffer, int length){ 
    int bytesLeft = length; 
    int bytesRead = 0; 

    while((bytesRead = qSocket_->read(buffer, bytesLeft)) > 0){ 
     bytesLeft -= bytesRead; 
     buffer += bytesRead; 

    } 
    return bytesLeft == 0; 
} 

我遇到的問題是有時從服務器的整個消息不是立即可用。

例如,前45個字節在客戶端可用。客戶端然後嘗試讀取整個消息(345字節),這會導致奇怪的行爲。在客戶端完成讀取後,立即可用下一個300字節。

在套接字之間發送消息的最佳方式是什麼?另外,如何確定是否收到了整個消息?

+1

TCP不提供任何類型的消息邊界,它只是一個字節流。您需要在循環中調用read(),直到獲得所有期望的數據。如果你發佈了'readXXX'函數的實現,那麼有人可能會提供更具體的建議。 – Barmar

+0

檢查更新的帖子。 – Carlj901

+0

看起來很對我。什麼是「怪異行爲」?假設套接字處於阻塞模式,'readString'應該等待接收整個消息。如果它處於非阻塞模式,則在調用'read()'時需要檢查'EWOULDBLOCK'錯誤。 – Barmar

回答

0

你有一些只存在於你腦海中的「消息」的概念。你的代碼沒有反映出這一點。如果您有涉及發送「消息」的應用程序協議,則需要編寫代碼以發送消息,並根據協議的消息定義接收消息。 TCP僅提供字節流,並且不會將它們粘貼到應用程序的任何大於一個字節的內容中。

相關問題