Я проследил исходный код linux по всему процессу отправки udp.
Я думаю, что возвращаемое значение sendto () возвращается rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK;
. Когда qdis c заполнен, он отбрасывает пакет и возвращает NET_XMIT_DROP
, затем значение будет преобразовано в ENOBUFS
.
Ниже приведен мой вопрос. Я написал клиентское приложение udp. Он отправил пакет udp, и я позволил ему непрерывно получать кадр паузы PF C, который вызывал переполнение буфера пакетов NI C, txring драйвера и qdis c. Однако
- sendto () блокируются в режиме блокировки и получают errno
EAGAIN
в неблокирующем режиме, что означает, что буфер сокета отправки UDP заполнен. Тем не менее, полный qdis c просто отбрасывает пакет, когда пакет ставится в очередь, почему буфер отправки UDP будет заполнен? - Нет
ENOBUFS
вернулось, даже если я установил длину qdis c меньше на ifconfig txqueuelen 10
. Программа выполнила setsockopt(sockfd, SOL_IP, IP_RECVERR,(char*)&val, sizeof(val));
, но не вернула ошибку. Поскольку есть несколько примеров использования IP_RECVERR, если в моем коде есть неправильное использование, пожалуйста, сообщите мне. Большое спасибо!
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <time.h>
#include <linux/errqueue.h>
#define UDP_TEST_PORT 5000
#define UDP_SERVER_IP "10.0.10.34"
int ip_control_msg( struct cmsghdr *msg )
{
int ret = 0;
switch( msg->cmsg_type ){
case IP_RECVERR:
{
struct sock_extended_err *exterr;
exterr = (struct sock_extended_err *)(CMSG_DATA(msg));
printf("ee_errno: %u\n", exterr->ee_errno );
printf("ee_origin: %u\n", exterr->ee_origin );
printf("ee_type: %u\n", exterr->ee_type );
printf("ee_code: %u\n", exterr->ee_code );
printf("ee_pad: %u\n", exterr->ee_pad );
printf("ee_info: %u\n", exterr->ee_info );
printf("ee_data: %u\n", exterr->ee_data );
}
ret = -1;
break;
default:
break;
}
return ret;
}
int control_msg( struct msghdr *msg )
{
int ret = 0;
struct cmsghdr *control_msg = CMSG_FIRSTHDR( msg );
while( control_msg != NULL ){
switch( control_msg->cmsg_level ){
case SOL_IP:
ret = ip_control_msg( control_msg );
break;
default:
break;
}
control_msg = CMSG_NXTHDR( msg, control_msg );
}
return ret;
}
int main(int argC, char* arg[])
{
struct sockaddr_in addr;
int sockfd, len = 0;
int addr_len = sizeof(struct sockaddr_in);
char buffer[4096];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
fcntl(sockfd,F_SETFL,O_NONBLOCK);
int val = 1;
setsockopt(sockfd, SOL_IP, IP_RECVERR,(char*)&val, sizeof(val));
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(UDP_TEST_PORT);
addr.sin_addr.s_addr = inet_addr(UDP_SERVER_IP);
int rtn = 0;
while(1) {
bzero(buffer, sizeof(buffer));
sprintf(buffer,"%d",cnt);
rtn = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, addr_len);
if(rtn<0){
printf("%d\n",errno);
}
char buf[1024];
char control_buf[1024];
struct msghdr msg;
struct iovec iov = { buf, 1024 };
memset( &msg, 0, sizeof(msg) );
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &control_buf;
msg.msg_controllen = 1024;
int bread = recvmsg( sockfd, &msg, MSG_ERRQUEUE );
if( bread == -1 ){
continue;
}
if( control_msg( &msg ) >= 0 )
printf("successed!\n");
else
printf("failed!\n");
}
return 0;
}