关于UDP接收icmp端口不可达(port unreachable)

本文将讲解为什么服务器回复端口不可达,以及客户端socket 如何获取 端口不可达 信号。

首先,做为服务器,当一个报文经过查路由,目的ip是上送本机的时候,经过netfilter 判决后,

调用ip_local_deliver_finish,它根据ip头中的协议类型(TCP/UDP/ICMP/......),调用不同的4层接口函数进行处理。

对于udp而言,handler 是udp_rcv,它直接调用了__udp4_lib_rcv,查找相应的sock,

如果sk不存在if(sk != NULL),就回复icmp destination unreachable,函数非常简单

所以作为服务器,收到一个目的端口并未监听的报文,直接回复端口不可达。

那么作为客户端,如何处理服务器回复的 端口不可达 报文呢?

起始当初想法很简单,我认为,不同的协议之间是不会干涉的,即TCP和UDP直接是不会干涉的。

何况这种不伦不类的icmp?后来想错了。

作为客户端,端口不可达报文进入ip_local_deliver_finish,它调用icmp_rcv函数,进行处理。(其实这也是当初

我认为客户端udp不会对端口不可达数据进行相应的原因,因为udp处理流程是udp_rcv)。

icmp_rcv函数最重要的是 它调用了:icmp_pointers[icmph->type].handler(skb);

handler = icmp_unreach

icmp_unreach函数最终的一步,就是它最后一步:

是不是很像ip_local_deliver_finish?

是很像,只是ip_local_deliver_finish中,调用了ipprot->handler,而这里调用了ipprot->err_handler

对于udp,err_handler = udp_err = __udp4_lib_err

在该函数中,只有进入如下的流程,应用程序才会反应:

先决条件是inet->recverr为非0,或者inet->recverr为0但是udp处于TCP_ESTABLISHED状态。

否则应用程序休想收到该端口不可达的数据,应用程序就等着read超时吧。所以说,为了获取udp端口不可达的情况

有2种方法:

法1:

对udp进行connect操作,并且将sendto改成send

法2:

int val = 1;

setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));

udp获知端口不可达的源程序

#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
unsigned char revc_buf[1024];

int main()
{
	int fd,ret,recv_len,size=1024;
	struct sockaddr_in server_addr,addr;
	int val = 1;
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr("192.168.2.254");
	server_addr.sin_port = htons(77);

	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(fd < 0)
	{
		perror("socket fail ");
		return -1;
	}

	printf("socket sucess\n");

        //方法2
	#if 1
	setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));
	if(sendto(fd, "nihao", strlen("nihao"), 0, (const struct sockaddr *)&(server_addr), sizeof(struct sockaddr_in))<0)
	{
		perror("sendto fail ");
		return -1;
	}
	printf("sendto sucess\n");
	recv_len = recvfrom(fd, revc_buf, sizeof(revc_buf), 0, (struct sockaddr *)&addr, (int *)&size);
	printf("recv_len:%d sucess\n");
	<span style="font-size:18px;"></span><pre name="code" class="cpp">        //方法1
	#elif 0
	ret = connect(fd, (const struct sockaddr *) &(server_addr), sizeof (struct sockaddr_in));
	if(ret < 0)
	{
		printf("connect fail\n");
		return -1;
	}

	ret = send(fd, "ni hao", strlen("nihao"),0);
	if(ret < 0)
	{
		printf("write fail\n");
		return -1;
	}

	ret = recvfrom(fd, revc_buf, sizeof(revc_buf), 0, (struct sockaddr *)&addr, (int *)&size);
	if(ret < 0)
	{
		printf("read fail\n");
		return -1;
	}
	#endif
	close(fd);

	return 0;
}
				
时间: 2024-08-25 22:18:17

关于UDP接收icmp端口不可达(port unreachable)的相关文章

UDP和ICMP之间的利用关系

场景说明:目前在windows上测试,或者在Linux上测试,发送UDP数据包,尽管目标端口不可达,但是并没有返回ICMP报文目的端口不可达的情况,真正做到了UDP报文的投递的特性,根本就没有等待,尽管调用了connect函数,但是没有任何的效果,其实我们可以想象到TCP的三次握手就是connect 函数的结果,但是UDP调用connect函数,却未必达到这个效果,因为UDP根本就没有三次握手,想来这个问题就可想而知的答案.但是根据<TCP/IP协议卷>,确实应该当UDP端口无法投递的时候,发

DNS同时占用UDP和TCP端口53——传输数据超过512时候用tcp,DNS服务器可以配置仅支持UDP查询包

DNS同时占用UDP和TCP端口53是公认的,这种单个应用协议同时使用两种传输协议的情况在TCP/IP栈也算是个另类.但很少有人知道DNS分别在什么情况下使用这两种协议. 先简单介绍下TCP与UDP.     TCP是一种面向连接的协议,提供可靠的数据传输,一般服务质量要求比较高的情况,使用这个协议.UDP---用户数据报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务. TCP与UDP的区别:     UDP和TCP协议的主要区别是两者在如何实现信息的可靠传递方面不同.TC

xcode中的udp接收数据

1.udpclient的初始化 udpClient=[[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:mainQueue]; udpClient.delegate=self; NSError *err; BOOL bret=[udpClient bindToPort:8009 error:&err];  //绑定接收数据用的端口 BOOL ret=[udpClient beginReceiving:&err ];

第九章 TCP和UDP同一时候用复用一个port实现一个回射server

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> #include

linux socket TCP UDP bind 同义IP和port

//TCP and UDP can bind to the same IP & port. #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include &

线程带参数的Udp接收

//work wk = new work(ReadUdpDate); ParameterizedThreadStart parmThre = new ParameterizedThreadStart(ReadUdpDate); Thread read = new Thread(parmThre); read.Start(ipAddress); private void ReadUdpDate(object IP) { string message = ""; try { while (

python打印系统所有tcp,udp监听端口及服务

#!/usr/local/bin/python3 #coding:utf-8 import string, subprocess tcptmpStr = ((subprocess.check_output(["netstat", "-ntlp"])).decode('utf-8')).strip() udptmpStr = ((subprocess.check_output(["netstat", "-nulp"])).dec

TCP、UDP和ICMP(面试题)

1.TCP传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据.TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端.2.UDP用户数据报协议,是一个简单的面向数据报的运输层协议.UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地.由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快.3.ICM

udp接收

char receive_buffer[500] = {0}; std::vector<std::string> mysplit(std::string str,std::string pattern) { std::string::size_type pos; std::vector<std::string> result; str+=pattern;//扩展字符串以方便操作 int size=str.size(); for(int i=0; i<size; i++) {