gpt4 book ai didi

linux - 创建 SOCK_RAW 套接字只是为了发送数据而不需要任何 recvform()

转载 作者:IT王子 更新时间:2023-10-29 00:21:18 27 4
gpt4 key购买 nike

如果我创建一个类型为 SOCK_RAW 的套接字仅发送一些数据而不接收任何数据,当内核继续接收网络数据包并将其数据报复制到某个缓冲区(应用程序?)时是否有任何问题。也就是说,somebuffer被填满后会发生什么?错误还是忽略?

我不知道如何防止内核将数据报副本传送到我的应用程序。

引用 http://sock-raw.org/papers/sock_raw 0x4 原始输入

IP层处理后一个新传入的 IP 数据报,它调用 ip_local_deliver_finish() 内核函数它负责调用已注册的传输协议(protocol)处理程序检查 IP header 的协议(protocol)字段(记住上面的内容)。然而在将数据报传递给处理程序之前,它每次都会检查是否应用程序创建了一个具有相同 协议(protocol)号的原始套接字。如果有是一个或多个这样的应用程序,它制作数据报的副本并传递对他们也是如此。

最佳答案

您可以使用shutdown(2) 来关闭套接字的接收部分。参见 shutdown man page

编辑: 我发现shutdown 仅适用于连接的(即 TCP)套接字。使用原始套接字,有两种可能性:

  • 将数据接收到临时缓冲区(使用recv)并丢弃它们(可能在其他线程中)
  • 如果我没记错的话,当套接字缓冲区已满时,传入的数据会自动丢弃(并且缓冲区中的数据不会被修改),因此您可以将套接字接收缓冲区大小设置为 0(如果需要,稍后可以增加它) ).

以下是将接收缓冲区大小设置为 0 的方法:

int opt = 0;
setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));

测试

/**
* @file raw_print_pkt.c
* @brief
* @author Airead Fan <fgh1987168@gmail.com>
* @date 2012/08/22 12:35:22
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

int main(int argc, char *argv[])
{
int s;
ssize_t rn; /* receive number */
struct sockaddr_in saddr;
char packet[4096];
int count;

if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}

memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(saddr);
int fromlen = sizeof(saddr);
int opt = 0;

count = 0;
while(1) {
if ((rn = recvfrom(s, (char *)&packet, sizeof(packet), 0,
(struct sockaddr *)&saddr, &fromlen)) < 0)
perror("packet receive error:");
if (rn == 0) {
printf("the peer has performed an orderly shutdown\n");
break;
}

printf("[%d] rn = %lu \n", count++, rn);

if (count == 16) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
perror("setsocketopt failed");
} else {
fprintf(stdout, "setsocketopt successful\n");
}
// int shutdown(int sockfd, int how);
/* if (shutdown(s, SHUT_RD) < 0) {
* perror("shutdown failed");
* } */
}
}

return 0;
}

测试 2(同样包括):

int main(int argc, char *argv[])
{
int s;
ssize_t rn; /* receive number */
char packet[4096];
int count;

if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}

memset(packet, 0, sizeof(packet));
int opt = 0;
count = 0;

//Set recv buffer size
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
perror("setsocketopt failed");
} else {
fprintf(stdout, "setsocketopt successful\n");
}

//10 seconds countdown
int i = 10;
while(i > 0)
{
printf("\r%d ", i);
fflush(stdout);
i--;
sleep(1);
}
printf("\n");
while(1) {
if ((rn = recv(s, (char *)&packet, sizeof(packet), 0)) <= 0)
perror("packet receive error:");

printf("[%d] rn = %lu \n", count++, rn);
}
return 0;
}

下面是如何进行测试 2:

首先,将缓冲区大小设置为 4096(如果您的网络流量很大,则设置更大)。编译并启动。在开始接收数据前的 10 秒内,向套接字发送大量数据。 10 秒后,程序将收到您在倒计时期间发送的所有内容。

之后,将缓冲区大小设置为 0。如前所述继续。 10 秒后,程序将不会收到您在倒计时期间发送的数据。但是,如果您在 recvfrom 中发送数据,它会正常读取它们。

关于linux - 创建 SOCK_RAW 套接字只是为了发送数据而不需要任何 recvform(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12065584/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com