views:

35

answers:

1

Hi there,

I am not very familiar with winsock or network programming, so I hope you forgive me if I am asking stupid stuff :)

I develop a client/server application which share some camera images. The general cycle is:

  1. The client captures a camera image and compress it to an binary image. After that it sends it to the server
  2. The server exactly knows how large the buffer is (640*480/8 bytes) so he is able to receive the hole image with only one recv-call. The next recv-call will get the second image and so on
  3. After receiving the image the server works with the image and will then send another image back to the client. But here is the problem: The image is jpeg compressed and so the client doesn't know the filesize and can't receive the image like the server with a fixed bufferlength.

I think that wouldn't be a problem if the server would close the connection after sending the image. But I don't want to close the connection because in the next cycle I will send the next image over the same connection.

My question is: How can I tell the client that the server send the hole image without closing the connection?

Here's some code: (The client sends the binary image to the server)

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

}

(The server receives the image with only one 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;
}

}

(Now the Server works with the image and send another jpeg compressed image back)

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());

}

(And the client doesn't know how large the buffer is so it receives 512Byte parts)

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;

}

with the while (iResult >= DEFAULT_BUFFER_LEN) I thought it will stop the receiving (because if a part is smaller than 512Bytes it must be the end). But my recvBuf only contains the last Bytes.

Maybe it's possible that I don't understand the hole winsock stuff, but I thought that the recvBuf will contain the hole buffer I received. Is that wrong? How do I get the hole received buffer without closing the connection?

I hope my question is clear

Ben

+2  A: 
  1. Don't rely on single calls to recv() and send() being able to run to completion and process the amount of data you asked for. You must be prepared to run them several times in a loop until the desired amount of data has been transferred.

  2. For the case when the server wants to return an image of unknown length, simply send the length first, using a well-defined format (for instance a 32-bit integer in network byte order). The client can then do two separate receives, one for the size and one for the data. Again, that doesn't mean it can simply do two recv() calls.

unwind
Ok that's a try. But how do I get the hole buffer after calling recv several times? On my client site I call recv several times but if I leave the loop there are only the bytes of my last recv-call in the buffer.
ben
@ben: When you call `recv()` multiple times with the same buffer, you're asking it to overwrite that buffer with the new data. So either call it with a different buffer, a later address within the same buffer, or copy the data out of the buffer first.
caf
@caf: thanks for that. I'm wondering why I didn't find an example for that yet, it seems to be a common problem.
ben