Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1334880
  • 博文数量: 284
  • 博客积分: 3251
  • 博客等级: 中校
  • 技术积分: 3046
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-26 17:23
文章分类

全部博文(284)

文章存档

2019年(2)

2018年(5)

2015年(19)

2014年(13)

2013年(10)

2012年(235)

分类: LINUX

2012-12-21 16:28:28

 在前一篇中,我们提到在对端主机上没有创建指定的UDP套接字时,我们向其发送一个UDP包,会得到一个目的端口不可达的ICMP出错报文。但内核在处 理完该报文后,给应用程序仅仅返回一个ECONNREFUSED错误号,所以应用程序能知道的全部信息就是连接被拒绝,至于为什么被拒绝,没有办法知道。 我们可以通过套接字选项的设置,让内核返回更为详细的出错信息,以利于调试程序,发现问题。下面是通过套接字选项传递扩展出错信息的一个示例程序。关于内 核原理的分析,在下一篇给出。
#include
#include
#include
#include
#include "my_inet.h"
#include
#include
#include

#include
#include

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 i;
    struct sockaddr_in dest;
    dest.sin_family = MY_PF_INET;
    dest.sin_port = htons(16000);
    dest.sin_addr.s_addr = 0x013010AC;

    int fd = socket( MY_PF_INET, SOCK_DGRAM, MY_IPPROTO_UDP );
    if( fd < 0 ){
        perror("socket: ");
        return -1;
    }
    if( connect( fd, (struct sockaddr*)&dest, sizeof(dest) ) < 0 ){
        perror("connect: ");
        return -1;
    }

    int val = 1;
    if( setsockopt( fd, SOL_IP, IP_RECVERR, &val, sizeof(val) ) == -1 ){
        perror("setsockopt: ");
        return -1;
    }

    int bwrite = send( fd, "abcdefg", 7, 0 );
    if( bwrite == -1 ){
        perror("send: ");
        return -1;
    }
    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( fd, &msg, MSG_ERRQUEUE );
    if( bread == -1 ){
        perror("recv: ");
        return -1;
    }
    if( control_msg( &msg ) >= 0 )
        printf("successed!/n");
    else
        printf("failed!/n");

    close( fd );
    return 0;
}

执行结果:
    ee_errno: 111           //ECONNREFUSED
    ee_origin: 2            //SO_EE_ORIGIN_ICMP
    ee_type: 3              //目的不可达
    ee_code: 3              //端口不可达
    ee_pad: 0
    ee_info: 0
    ee_data: 0
    failed!
阅读(480) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~