2010-09-22 6 views
1

Je développe une application client/serveur qui partage des images de caméra. Le cycle général est:Winsock: Comment arrêter l'envoi/la réception sans fermer la connexion

  1. Le client capture une image de caméra et la compresse en une image binaire. Après cela, il l'envoie au serveur
  2. Le serveur connaît exactement la taille du tampon (640 * 480/8 octets), ce qui lui permet de recevoir l'image du trou avec un seul appel recv. Le prochain appel recv obtiendra la deuxième image et ainsi de suite
  3. Après avoir reçu l'image, le serveur travaille avec l'image et enverra ensuite une autre image au client. Mais voici le problème: L'image est compressée en JPEG et donc le client ne connaît pas la taille du fichier et ne peut pas recevoir l'image comme le serveur avec une longueur de buffer fixe.

Je pense que ce ne serait pas un problème si le serveur fermait la connexion après l'envoi de l'image. Mais je ne veux pas fermer la connexion parce que dans le cycle suivant, je vais envoyer l'image suivante sur la même connexion.

Ma question est: Comment puis-je dire au client que le serveur envoie l'image du trou sans fermer la connexion?

Voici quelques code: (Le client envoie l'image binaire au serveur)

void sendToServer(char* sendbuf, int sendbuflen) { 
    int iResult = send(ConnectSocket, sendbuf, sendbuflen, 0); 
    if (iResult == SOCKET_ERROR) { 
     (*errCallbackFunc)("Sending image error", -1); 
    } 
} 

(Le serveur reçoit l'image avec une seule functioncall - recbuflen = 640 * 480/8)

int receiveCameraImages(ARUint8* dataPtr) { 
int   iResult; 

iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 
if (iResult > 0) { 
    if ((*(recvbuf+0)) != 'U' || (*(recvbuf+((xsize*ysize/8)-1))) != 'U') 
     return RECEIVING_INCOMPLETE; 

    convertBWChartoBGR(recvbuf, dataPtr, recvbuflen); 

    return RECEIVING_SUCCEEDED; 
} else if (iResult == 0) { 
    (*errCallbackFunc)("Connection closing", -1); 
    return RECEIVING_CONN_CLOSED; 
} 
else { 
    (*errCallbackFunc)("recv failed", WSAGetLastError()); 
    return RECEIVING_ERROR; 
} 
} 

(maintenant, le serveur fonctionne avec l'image et envoyer une autre jpeg image compressée retour)

int sendObjectImage(ARUint8* dataPtr, int bufLen) { 
int iResult; 

/* send the openGLBuffer back to the client */ 
iResult = send(ClientSocket, dataPtr, bufLen, 0); 
if (iResult == SOCKET_ERROR) (*errCallbackFunc)("send openglbuffer back to client failed", WSAGetLastError()); 
} 

(Et le client ne sait pas la taille de la mémoire tampon est donc il reçoit des parties 512Byte)

int receiveFromServer(ARUint8* dataPtr) { 
int iResult, returnBufLen = 0; 
int recvBufLen = DEFAULT_BUFFER_LEN; 
ARUint8 recvBuf[DEFAULT_BUFFER_LEN]; 

/* receive openGL buffer */ 
do { 
    iResult = recv(ConnectSocket, recvBuf, recvBufLen, 0); 
    if (iResult > 0) { 
     printf("Bytes received: %d\n", iResult); 
     returnBufLen += iResult; 
    } 
    else if (iResult == 0) 
     printf("Connection closed\n"); 
    else 
     printf("recv failed: %d\n", WSAGetLastError()); 
} while (iResult >= DEFAULT_BUFFER_LEN); 

dataPtr = recvBuf; 

return returnBufLen; 
} 

avec le temps (iResult> = DEFAULT_BUFFER_LEN) Je pensais qu'il arrête la réception (parce que si une partie est plus petit que 512Bytes il doit être la fin). Mais mon recvBuf ne contient que les derniers octets.

Peut-être qu'il est possible que je ne comprenne pas les trucs de trous winsock, mais je pensais que le recvBuf contiendra le tampon de trou que j'ai reçu. Est-ce faux? Comment puis-je obtenir le buffer reçu sans fermer la connexion?

Répondre

4
  1. Ne comptez pas sur les appels à un seul recv() et send() être en mesure d'exécuter à la fin et traiter la quantité de données que vous avez demandé. Vous devez être prêt à les exécuter plusieurs fois dans une boucle jusqu'à ce que la quantité de données souhaitée ait été transférée. Dans le cas où le serveur veut renvoyer une image de longueur inconnue, il suffit d'envoyer la longueur en premier, en utilisant un format bien défini (par exemple un entier de 32 bits dans l'ordre des octets du réseau). Le client peut alors faire deux reçus distincts, un pour la taille et un pour les données. Encore une fois, que ne signifie qu'il peut simplement faire deux recv() appels.

+0

Ok c'est un essai. Mais comment puis-je obtenir le tampon de trou après avoir appelé recv plusieurs fois?Sur mon site client, j'appelle recv plusieurs fois mais si je quitte la boucle, il n'y a que les octets de mon dernier appel recv dans le buffer. – ben

+0

@ben: Lorsque vous appelez 'recv()' plusieurs fois avec le même tampon, vous lui demandez d'écraser ce tampon avec les nouvelles données. Donc, appelez-le avec un tampon différent, une adresse plus récente dans le même tampon ou copiez d'abord les données dans le tampon. – caf

+0

@caf: merci pour cela. Je me demande pourquoi je n'ai pas encore trouvé d'exemple pour cela, cela semble être un problème courant. – ben

Questions connexes