好记性不如铅笔头

C && C++, 编程, 网络通讯

关于UDP接收icmp端口不可达的获取方式

本文转自【 https://blog.csdn.net/mrpre/article/details/43451775 】,有大量删改。

有时候,写UDP socket程序的时候,在调用sendto或者recvfrom的时候,会发现有Connection refused错误返回,错误码是ECONNREFUSED。

ECONNREFUSED
A remote host refused to allow the network connection (typically because it is not running the requested service).

ICMP错误信息返回时,ICMP的包内容就是出错的那个原始数据包,根据这个原始数据包可以找出一个五元组,根据该五元组就可以对应到一个本地的connect过的UDP socket,进而把错误消息传输给该socket,应用程序在调用socket接口函数的时候,就可以得到该错误消息。如果一个UDP socket没有调用过connect,那么即使有ICMP数据包返回,由于socket保持了UDP的完整语义,协议栈也就不保存关于该socket和对端关联的任何信息,因此也就无法找到一个特定的五元组将错误码传给它。

为了获取udp端口不可达的情况,有2种方法:
法1:
对udp进行connect操作,并且将sendto改成send
法2:
int val = 1;
setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));

参考实例代码:

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");  
    //方法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;  
}

 

发表评论

2 × 4 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据