根据http://man7.org/linux/man-pages/man7/packet.7.html ,自linux 3.14以来有一个新的选项PACKET_QDISC_BYPASS。 这有可能更快地发送和接收数据包。
看到一个示例代码: https : //github.com/netoptimizer/network-testing/blob/master/src/raw_packet_send.c ,但不幸的是它没有发送数据包的代码。
我添加了一些代码来发送数据包,但是sendto有问题。
# ./raw_packet_send p6p1 64 Lame RAW/PF_PACKET socket TX test program Enabled kernel qdisc bypass error sendto : Invalid argument
不知道为什么。 这里是代码(原始raw_packet_send.c与我愚蠢的代码)。 请让我知道如何使它工作或指向我一些很好的简单的示例代码。 谢谢。
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <unistd.h> #include <linux/if_packet.h> #include <errno.h> #include <sys/ioctl.h> #include <net/if.h> #include <netinet/in.h> //#include <stdio.h> //#include <sys/types.h> //#include <sys/stat.h> //#include <sys/socket.h> //#include <sys/mman.h> //#include <linux/filter.h> //#include <ctype.h> //#include <fcntl.h> //#include <unistd.h> //#include <bits/wordsize.h> //#include <net/ethernet.h> //#include <netinet/ip.h> //#include <arpa/inet.h> //#include <stdint.h> //#include <string.h> //#include <assert.h> //#include <net/if.h> //#include <inttypes.h> //#include <poll.h> //#include <unistd.h> #ifndef PACKET_QDISC_BYPASS #define PACKET_QDISC_BYPASS 20 #endif #include "common_socket.h" char pkt[2000] = {0x00, 1,2,3,4,0, 0,1,2,3,4,1, 8, 0};; int len = 96; char intfName[100] = "em1"; /* Avail in kernel >= 3.14 * in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option) */ void set_sock_qdisc_bypass(int fd, int verbose) { int ret, val = 1; ret = setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &val, sizeof(val)); if (ret < 0) { printf("[DEBUG] %s(): err:%d errno:%d\n", __func__, ret, errno); if (errno == ENOPROTOOPT) { if (verbose) printf("No kernel support for PACKET_QDISC_BYPASS" " (kernel < 3.14?)\n"); } else { perror("Cannot set PACKET_QDISC_BYPASS"); } } else if (verbose) printf("Enabled kernel qdisc bypass\n"); } int pf_tx_socket(int ver) { int ret, val = 1; /* Don't use proto htons(ETH_P_ALL) as we only want to transmit */ int sock = socket(PF_PACKET, SOCK_RAW, 0); //int sock = socket(AF_INET,SOCK_PACKET,htons(3)); if (sock == -1) { perror("Creation of RAW PF_SOCKET failed!\n"); exit(1); } ret = Setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver)); return sock; } void mybind(int sock, char *intf) { struct ifreq ifr; int rc; memset((char*)&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), intf); if ((rc = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0) { perror("Server-setsockopt() error for SO_BINDTODEVICE"); printf("%s\n", strerror(errno)); close(sock); exit(-1); } } int flood (int sock) { struct sockaddr intfAddrs; char cmd[100]; int tmp; memset((char*)&intfAddrs, 0, sizeof (struct sockaddr)); intfAddrs.sa_family = PF_PACKET; strcpy((char*)(intfAddrs.sa_data), intfName); sprintf(cmd, "ifconfig %s promisc", intfName); system(cmd); while (1) { while (1) { tmp = sendto(sock, pkt, len, 0, &intfAddrs, sizeof(intfAddrs)); if (tmp != len) {perror("error sendto "); exit(0); } } } } int main(int argc, char **argv) { if (argc > 1) { strcpy(intfName, argv[1]); } if (argc > 2) { len = atoi(argv[2]); } printf("Lame RAW/PF_PACKET socket TX test program\n"); int sock = pf_tx_socket(0); set_sock_qdisc_bypass(sock, 1); mybind(sock, intfName); flood(sock); return 0; }
我认为你需要改变PF_PACKET
AF_PACKET
(虽然它看起来 PF_PACKET
是PF_PACKET
的别名),但我没有任何成功的时候使用PF_PACKET
。
这段代码适用于我:
// Create a raw socket sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock_fd == -1) { perror("Can't create AF_PACKET socket"); return EXIT_FAILURE; } // Check kernel version static const int32_t sock_qdisc_bypass = 1; int32_t sock_qdisc_ret = setsockopt(thd_opt->sock_fd, SOL_PACKET, PACKET_QDISC_BYPASS, &sock_qdisc_bypass, sizeof(sock_qdisc_bypass)); if (sock_qdisc_ret == -1) { perror("Can't enable QDISC bypass on socket"); return EXIT_FAILURE; }
这是来自setup_socket_mmap()
这里的