Какие часы использует опция сокета SO_TIMESTAMP? - PullRequest
3 голосов
/ 01 апреля 2020

Я получаю поток сообщений от TCP-сервера (робот отправляет свой статус) каждые 0,1 с. Я не могу гарантировать, что я звоню recvmsg каждые 0,1 с, поэтому я хотел бы иметь временную отметку для этих полученных сообщений, чтобы, когда я их recvmsg знал, я только что получил их, или если они находились в буфере достаточно долго, чтобы быть устаревшим, и мне следует снова вызывать recvmsg, пока я не прочитаю недавнее сообщение.

Прежде всего, что clock делает struct timespec из отметки времени SO_TIMESTAMP? Я нашел источники в Google, которые указывают на CLOCK_REALTIME, но им около 10 лет, поэтому они могут быть устаревшими.

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

Можно ли использовать CLOCK_BOOTTIME, чтобы избежать проблем с непрерывностью?


Я допустил ошибку. Я смешал SO_TIMESTAMP (использует struct timeval) с SO_TIMESTAMPNS (использует struct timespec) (SO_TIMESTAMPNS не представляется доступным).

Хотя SO_TIMESTAMPNS не представляется доступным согласно документации , когда я #include <sys/socket.h> у меня это определено как 35.

Ответы [ 2 ]

1 голос
/ 02 апреля 2020

Используется CLOCK_REALTIME.

Слойка. Итак: SO_TIMESTAMP упоминается в sock_setsockopt. Оттуда я прыгнул до sock_enable_timestamp. Но прямо над этой функцией стоит sock_get_timestamp и sock_get_timestampns. Они используют ktime_get_real. Просто для проверки sock_get_timestamp используется в inet_ioctl в af_ inet. c. Просто чтобы быть больным, я исследовал документацию по ktime-аксессорам , что ktime_get_real совпадает с CLOCK_REALTIME. И ktime_get_real также используется __net_timestamp в буфере сокета

1 голос
/ 02 апреля 2020

ОБНОВЛЕНИЕ: Документация отсутствовала, поэтому я написал ее. Это задокументировано в man 7 socket в версии 5.06 man-страниц.


Экспериментально , SO_TIMESTAMPNS работает, и похоже, что он использует CLOCK_REALTIME.

Следовательно, функция, которая будет использоваться с SO_TIMESTAMPNS, имеет вид clock_gettime(CLOCK_REALTIME, &tm);


Я не знаю конкретной c документации для нее, но я сделал некоторый эксперимент:

Я написал простой тест сервера и клиента.

На стороне клиента я подключил сокет, указав SOCK_STREAM и "tcp".

Затем я включенная метка времени в нс:

    int     enable = 1;

    if (setsockopt(sd, SOL_SOCKET, SO_TIMESTAMPNS, &enable,
                                                    sizeof(enable)))
            goto err;

Затем я подготовил заголовок сообщения:

    char            buf[BUFSIZ];
    char            cbuf[BUFSIZ];
    struct msghdr   msg;
    struct iovec    iov;

    iov.iov_base    = buf;
    memset(buf, 0, ARRAY_BYTES(buf));
    iov.iov_len     = ARRAY_BYTES(buf) - 1;
    msg.msg_name    = NULL;
    msg.msg_iov     = &iov;
    msg.msg_iovlen  = 1;
    msg.msg_control = cbuf;
    msg.msg_controllen = ARRAY_BYTES(cbuf);

И получил несколько раз до и после получения сообщения:

    struct timespec tm_before, tm_recvmsg, tm_after, tm_msg;

    clock_gettime(CLOCK_REALTIME, &tm_before);
    usleep(500000);
    clock_gettime(CLOCK_REALTIME, &tm_recvmsg);
    n   = recvmsg(sd, &msg, MSG_WAITALL);
    if (n < 0)
            goto err;
    usleep(1000000);
    clock_gettime(CLOCK_REALTIME, &tm_after);

После этого я прочитал метку времени сообщения:

    struct cmsghdr  *cmsg;

    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
            if (cmsg->cmsg_level == SOL_SOCKET  &&
                                    cmsg->cmsg_type == SCM_TIMESTAMPNS) {
                    memcpy(&tm_msg, CMSG_DATA(cmsg), sizeof(tm_msg));
                    break;
            }
    }
    if (!cmsg)
            goto err;

и наконец напечатал результаты:

    double      tdiff;

    printf("%s\n", buf);
    tdiff   = timespec_diff_ms(&tm_before, &tm_recvmsg);
    printf("tm_r - tm_b = %lf ms\n", tdiff);
    tdiff   = timespec_diff_ms(&tm_before, &tm_after);
    printf("tm_a - tm_b = %lf ms\n", tdiff);
    tdiff   = timespec_diff_ms(&tm_before, &tm_msg);
    printf("tm_m - tm_b = %lf ms\n", tdiff);

Который напечатал:

asdasdfasdfasdfadfgdfghfthgujty 6, 0;

tm_r - tm_b = 500.000000 ms
tm_a - tm_b = 1500.000000 ms
tm_m - tm_b = 18.000000 ms

Система :

Linux debian 5.4.0-4-amd64 #1 SMP Debian 5.4.19-1 (2020-02-13) x86_64 GNU/Linux
gcc (Debian 9.3.0-8) 9.3.0

Однако я не нашел ни одной справочной страницы, которая бы говорила о SO_TIMESTAMPNS, так что это может не работать в других системах.


Я не сделал не тестирую SO_TIMESTAMP потому что это использует struct timeval, который AFAIK устарел .

...