Winsock: как остановить отправку / получение, не закрывая соединение - PullRequest
1 голос
/ 22 сентября 2010

Я разрабатываю клиент-серверное приложение, которое делится некоторыми изображениями с камеры. Общий цикл:

  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) Я думал, что это прекратит прием (потому что если часть меньше 512 байт, она должна быть концом) Но мой recvBuf содержит только последние байты.

Возможно, возможно, что я не понимаю, что такое дырочный Winsock, но я думал, что recvBuf будет содержать буфер дырок, который я получил. Это неправильно? Как получить дыру полученный буфер без закрытия соединения?

1 Ответ

4 голосов
/ 22 сентября 2010
  1. Не надейтесь, что одиночные вызовы recv() и send() смогут завершиться и обработать объем данных, который вы запрашивали. Вы должны быть готовы запустить их несколько раз в цикле, пока не будет передан желаемый объем данных.

  2. Для случая, когда сервер хочет вернуть изображение неизвестной длины, просто сначала отправьте длину, используя четко определенный формат (например, 32-разрядное целое число в порядке сетевых байтов). Затем клиент может сделать два отдельных приема, один для размера и один для данных. Опять же, это не означает, что он может просто сделать два recv() вызова.

...