Я пытаюсь измерить скорость UDP-сокетов в моей локальной сети.
Проверяя мой локальный IP-адрес, я получаю время прохождения сигнала туда и обратно около 80 микросекунд.
Я написал минимальный UDP-сервер и клиент для измерения задержки следующим образом. Клиент и сервер работают на одном хосте, используя один и тот же сетевой интерфейс. Клиент отправляет timeval на сервер через датаграммные сокеты, и после получения сервер немедленно берет разницу между текущим timeval и полученным timeval. Сделав это, я получаю ~110 микросекунд для одностороннего пути, что в сумме составляет около ~220 микросекунд RTT.
Почему ping работает намного быстрее моей программы?
cc udpserver.c -o udpserver
cc udpclient.c -o udpclient
./udpserver 4321
./udpclient 127.0.0.1 4321
udpserver.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
struct timeval tval_recv, tval_now;
struct sockaddr_in serv_addr;
int n;
/* Check arguments */
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
/* Set up socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* Setup socket address for server */
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(atoi(argv[1]));
/* Bind socket to socket address */
if(bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
while(1) {
n = recvfrom(sockfd, &tval_recv, sizeof(tval_recv), 0, NULL, NULL);
if(n < 0)
error("ERROR in recvfrom");
gettimeofday(&tval_now, NULL);
printf("%ld.%06ld\n", tval_now.tv_sec - tval_recv.tv_sec,
(long int)(tval_now.tv_usec - tval_recv.tv_usec));
}
return 0;
}
udpclient.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(char *msg) {
perror(msg);
exit(0);
}
int main(int argc, char **argv) {
in_addr_t s_addr;
int sockfd, portno, n;
struct sockaddr_in serveraddr;
struct timeval tval;
// struct timespec ts_current;
/* Check arguments */
if (argc != 3) {
fprintf(stderr,"Usage: %s <hostname> <port>\n", argv[0]);
exit(0);
}
/* Create the socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("Error opening socket");
/* Set the socket address */
s_addr = inet_addr(argv[1]);
portno = atoi(argv[2]);
memset((char *) &serveraddr, '\0', sizeof(serveraddr));
memcpy(&serveraddr.sin_addr.s_addr, &s_addr, sizeof(s_addr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
/* Send packets */
while(1) {
gettimeofday(&tval, NULL);
// clock_gettime(CLOCK_MONOTONIC, &ts_current);
n = sendto(sockfd, &tval, sizeof(tval), 0, (struct sockaddr *)&serveraddr,
sizeof(serveraddr));
if(n < 0)
error("ERROR in sendto");
sleep(1);
}
return 0;
}
решение1
Грубое предположение:
ping
— это инструмент, использующий icmp
протокол. icmp
находится на уровне 3, сетевом уровне модели OSI.
udpclient.c
— это инструмент, использующий udp
протокол. udp
находится на уровне 4, транспортном уровне, модели OSI.
С каждым уровнем к необработанным данным будут добавляться дополнительные данные. Вот простой пример: пакет icmp
содержит исходный IP-адрес и IP-адрес назначения. udp
Дейтаграмма содержит все это плюс, например, информацию о порте UDP. Эта информация о порте должна интерпретироваться более высоким уровнем в сетевом стеке.
Поэтому пакеты UDP должны подняться на один уровень выше в сетевом стеке. Можно представить, что вы поднимаетесь по лестнице на 4-й этаж вместо 3-го. Это займет больше времени, однако гораздо больше, чем 30 мкс.
Я считаю, что эти 30 мкс состоят из
- размер данных
icmp
противudp
- Время сетевой карты / драйвера / процессора для инкапсуляции и декапсуляции
- Процессорное время, которое
udpclient.c
использует