Winsock:如何在不关闭连接的情况下停止发送/接收

发布于 2024-09-24 11:06:43 字数 2455 浏览 6 评论 0原文

我开发了一个共享一些相机图像的客户端/服务器应用程序。大致的周期是:

  1. 客户端捕获相机图像并将其压缩为二值图像。之后它将其发送到服务器
  2. 服务器确切地知道缓冲区有多大(640*480/8字节),因此他只需一次recv调用就可以接收孔图像。下一个recv调用将获取第二个图像,依此类推。
  3. 接收到图像后,服务器处理该图像,然后将另一个图像发送回客户端。但问题是:图像是 jpeg 压缩的,因此客户端不知道文件大小,并且无法像具有固定缓冲区长度的服务器一样接收图像。

我认为如果服务器在发送图像后关闭连接,那不会有问题。但我不想关闭连接,因为在下一个周期中我将通过同一连接发送下一个图像。

我的问题是:如何在不关闭连接的情况下告诉客户端服务器发送了孔图像?

这是一些代码: (客户端将二进制图像发送到服务器)

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;
}

与 while (iResult >= DEFAULT_BUFFER_LEN) 我认为它会停止接收(因为如果一个部分小于 512Bytes 它一定是结束)。但我的recvBuf只包含最后一个字节。

也许我不理解孔winsock的东西,但我认为recvBuf将包含我收到的孔缓冲区。这是错误的吗?如何在不关闭连接的情况下获取洞接收缓冲区?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

热情消退 2024-10-01 11:06:43
  1. 不要依赖对 recv()send() 的单个调用能够运行完成并处理您请求的数据量。您必须准备好在循环中多次运行它们,直到传输了所需的数据量。

  2. 对于服务器想要返回未知长度的图像的情况,只需首先使用明确定义的格式(例如网络字节顺序的 32 位整数)发送长度即可。然后,客户端可以执行两次单独的接收,一次接收大小,另一次接收数据。同样,这并不意味着它可以简单地执行两次recv()调用。

  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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文