我开发了一个共享一些相机图像的客户端/服务器应用程序。一般周期是:
如果服务器在发送图像后关闭连接,我认为这不会有问题。但我不想关闭连接,因为在下一个周期中,我将通过同一连接发送下一个图像。
我的问题是:如何告诉客户端服务器在不关闭连接的情况下发送孔图像?
这是一些代码: (客户端将二进制映像发送到服务器)
void sendToServer(char* sendbuf, int sendbuflen) {
int iResult = send(ConnectSocket, sendbuf, sendbuflen, 0);
if (iResult == SOCKET_ERROR) {
(*errCallbackFunc)("Sending image error", -1);
}
}
(服务器接收只有一个功能的图像 - 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;
}
}
(现在服务器处理图像并发回另一个jpeg压缩图像)
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());
}
(并且客户端不知道缓冲区有多大,因此它接收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;
}
with while(iResult> = DEFAULT_BUFFER_LEN)我认为它会停止接收(因为如果一个部分小于512Bytes,它必须是结束)。但我的recvBuf只包含最后一个字节。
也许我可能不理解孔winsock的东西,但我认为recvBuf将包含我收到的空洞缓冲区。那是错的吗?如何在不关闭连接的情况下获得孔接收缓冲区?
答案 0 :(得分:4)
不要依赖对recv()
和send()
的单次调用才能运行完成并处理您要求的数据量。您必须准备好循环运行它们几次,直到传输了所需数量的数据。
对于服务器想要返回未知长度的图像的情况,只需先使用定义良好的格式(例如网络字节顺序为32位整数)发送长度。然后,客户端可以执行两个单独的接收,一个用于大小,一个用于数据。同样,不意味着它只能进行两次recv()
次呼叫。