LINUX.ORG.RU

получаю несобранный пакет


0

0

Други! из-за чего может быть такая фигня: обмен по сетке через сокет.

сервер: send(); receive();

клиент: receive(); send();

отправляется пакет больше MTU=1500. иногда клиент получает 1448 байт (МТУ - tcp-заголовок) с реальными данными, а потом оставшуюся часть пакета с нулями. замена send/receive на write/read несколько улучшила ситуацию, но в самом начале такая же хрень проскочила. дальше - части кода

сервер: s = socket (AF_INET, SOCK_STREAM, 0);

bind(s, (struct sockaddr *)&srv, sizeof(srv));

len=send (s, buf, len, 0);

len=recv (s, buf, len, 0);

клиент: s = socket (AF_INET, SOCK_STREAM, 0);

bind(s, (struct sockaddr *)&clnt, sizeof(clnt));

len=recv (s, buf, len, 0);

len=send (s, buf, len, 0);

Ситуация никогда не возникает, если оба участника обмена находятся на одной машине. :((

anonymous

Извини за наивный вопрос, но - всякое бывает ;)
А как ты MTU преодолеваешь? Типа, остаток пакета досылать не забываешь?

Die-Hard ★★★★★
()

разбивка на чанки подходящие под MTU происходит в IP леере ..
на уровне send() recv() ты можешь ничего не знать про MTU
заметим так же что
recv() без флагов пробует считать данные если они есть и вернет что будет блокировать
если данных нет - можешь попробовать MSG_WAITALL флаг.
вот можешь поэкспериментировать с функцией:

/*
 * (c) lg
 * NOT TESTED! USE ON YOUR OWN RISK!
 */
enum rs_types {
        RS_SEND = 0,
        RS_RECV
};

int
recvsend_exact(int how, int s, char *buf, size_t len, long timeo)
{
        struct timeval tv = {0,0}, *tvp = &tv;
        fd_set rfd;
        size_t togo, totalrs;
        size_t rsb;
        int n;

        if (timeo != 0)
                tvp->tv_sec = timeo;
        else
                tvp = NULL;

        togo = len;
        totalrs = 0;
        while (togo > 0) {
                FD_ZERO(&rfd);
                FD_SET(s, &rfd);
                switch (how) {
                        default:
                                /* XXX unknown type */
                                goto out;
                        case RS_RECV:
                                n = select(s + 1, &rfd, NULL, NULL, tvp);
                                break;
                        case RS_SEND:
                                n = select(s + 1, NULL, &rfd, NULL, tvp);
                                break;
                }

                if (n < 0) {
                        if (errno == EAGAIN) {
                                /* XXX */
                        }
                        if (errno == EINTR) {
                                /* XXX */
                                continue;
                        }
                        /* XXX select fail */
                        goto out;
                }
                if (n == 0) {
                        /* XXX select timeouted */
                        goto out;
                }
                if (FD_ISSET(s, &rfd)) {
                        switch (how) {
                                default:
                                        /* XXX should not happen */
                                        goto out;
                                case RS_RECV:
                                        rsb = recv(s, (void*)(buf + totalrs), togo, 0);
                                        break;
                                case RS_SEND:
                                        rsb = send(s, (void*)(buf + totalrs), togo, 0);
                                        break;
                        }

                        if (rsb < 1) {
                                /* XXX read/write failed or peer closed */
                                goto out;
                        }
                        totalrs += rsb;
                        togo -= rsb;
                } else {
                        /* XXX should not happen */
                        goto out;
                }
        }
out:
        return totalrs;
}

lg ★★
()
Ответ на: комментарий от lg

2lg (*) (2002-09-07 00:47:50.307):
> разбивка на чанки подходящие под MTU происходит в IP леере ..
Точно! :)

> на уровне send() recv() ты можешь ничего не знать про MTU
... пока об него не стукнешься.
Короче, если ты посылаешь 1024 байта, а послалось 512, то - ты стукнулся об
MTU. Я это много раз проходил :), хотя это - классический FAQ.


Die-Hard ★★★★★
()

эээ, спасибо, граждане! лучше man-ы читать надо :((, много времени экономится. воистину, век учись, и все равно дураком помрешь.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.