Winsock: How to stop sending/receiving without closing the connection
I develop a client/server application which share some camera images. The general cycle is:
- The client captures a camera image and compress it to an binary image. After that it sends it to the server
- 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
- 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 c开发者_Go百科lient 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?
Don't rely on single calls to
recv()
andsend()
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.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.
精彩评论