Невозможно отправить весь файл через TCP-соединение! (UNIX C) - PullRequest
2 голосов
/ 16 декабря 2011

Итак, я запрограммировал многопоточный веб-сервер, вот одна из функций программы. Эта функция принимает дескриптор выходного файла (fd), тип содержимого, указатель на обслуживаемые данные (*buf) и размер данных (numbytes). Это всегда застревает в 5775 байтах! Я пытался использовать write() вместо send(), но безрезультатно! Я пытался отправить целое buf за раз, и даже пытался передать его кусками, но wget показывает, что он получает stck на 5775 байт! Вот код:

int return_result(int fd, char *content_type, char *buf, int numbytes)
{
    char out_buf[BUF_SIZE], numb[6];
    int buf_len, total = 0, buf_size;
    long int i = 0;
    sprintf(numb, "%d", numbytes);
    strcpy(out_buf, "HTTP/1.1 200 OK \nContent-Type: ");
    strcat(out_buf, content_type);
    strcat(out_buf, "\nContent-Length: ");
    strcat(out_buf, numb);
    strcat(out_buf, "\nConnection: Close\n  \n");
    printf("\nSending HTTP Header\n %d bytes sent!",
           send(fd, out_buf, strlen(out_buf), 0));
    char *start = NULL, *str = NULL, *temp = NULL;
    start = buf;
    printf("\n Start Pointer Val = %ld", &start);
    while (start != NULL) {
        printf("\n While Loop");
        if (i + 2048 * sizeof(char) < numbytes) {
            printf("\n If 1");
            str = (char *)malloc(sizeof(char) * 2048);
            memcpy(str, start, sizeof(char) * 2048);
            i = i + 2048 * sizeof(char);
            buf_size = send(fd, str, 2048, 0);
            free(str);
            printf("\n Sent %d bytes total : %d", buf_size, total =
                   total + buf_size);

            temp = start + sizeof(char) * 2048;
            start = temp;

        } else {

            i = numbytes - i * sizeof(char);
            if (i > 0) {
                printf("\n If 2");
                printf("\n Value of i %d", i);
                str = (char *)malloc(sizeof(char) * i);
                memcpy(str, start, sizeof(char) * i);
                printf("Total bytes finally sent:%d", total =
                       total + send(fd, str, i, 0));
                if (total == numbytes) {
                    printf("\nTransfer Complete!");
                }
                free(str);

            }
            start = NULL;
        }
    }
    printf("out of loop!");
    return 0;
}

Ответы [ 2 ]

2 голосов
/ 16 декабря 2011

Я хотел бы предложить заменить ваш код следующей функцией writen() из Расширенное программирование в среде Unix, 2-е издание :

ssize_t             /* Write "n" bytes to a descriptor  */
writen(int fd, const void *ptr, size_t n)
{
        size_t          nleft;
        ssize_t         nwritten;

        nleft = n;
        while (nleft > 0) {
                if ((nwritten = write(fd, ptr, nleft)) < 0) {
                        if (nleft == n)
                                return(-1); /* error, return -1 */
                        else
                                break;      /* error, return amount written so far */
                } else if (nwritten == 0) {
                        break;
                }
                nleft -= nwritten;
                ptr   += nwritten;
        }
        return(n - nleft);      /* return >= 0 */
}

Этот код уже отлажени известная работа, а также позволяет write(2) писать PIPE_BUF байт на ходу для лучшей скорости, когда все работает хорошо.

send(2) должен блокировать, если он не может отправить вседанные, которые вы запросили, хотя.Я думаю, что более интересной была бы отладка версии с простым send(2) без каких-либо попыток разбить вещи на блоки.

Лучше, чем оба write(2) и send(2) были бы sendfile(2) - открытьфайл, передайте дескриптор и сокет в sendfile(2), и позвольте ядру обработать все это за вас, используя механизмы нулевого копирования, если это возможно.

И последнее замечание: HTTP использует CRLF , не простой возврат каретки.Каждый \n должен быть заменен на \r\n.

1 голос
/ 16 декабря 2011

Попробуйте что-то вроде этого (printf() операторы для ясности опущены):

int send_buf(in fd, void *buf, int numbytes)
{
    char *start = (char*) buf;
    while (numbytes > 0)
    {
        int sent = send(fd, start, numbytes, 0);
        if (sent <= 0)
        {
            if ((sent == -1) && (errno == EAGAIN))
            {
                fd_set wfds;
                FD_ZERO(&wfds);
                FD_SET(fd, &wfds);
                if (select(fd + 1, NULL, &wfds, NULL, NULL) == 1)
                    continue;
            }
            return -1;
        }

        start += sent;
        numbytes -= sent;
    }

    return 0;
}

int return_result(int fd, char *content_type, void *buf, int numbytes) 
{ 
    char out_buf[BUF_SIZE], 

    int len = sprintf(out_buf,
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: %s\r\n"
        "Content-Length: %d\r\n"
        "Connection: Close\r\n"
        "\r\n",
        content_type,
        numb); 

    if (send_buf(fd, out_buf, len) != 0)
        return -1;

    if (send_buf(fd, buf, numbytes) != 0)
        return -1;

    return 0; 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...