Chinaunix首页 | 论坛 | 博客
  • 博客访问: 365658
  • 博文数量: 166
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-21 17:29
文章分类

全部博文(166)

文章存档

2015年(60)

2014年(99)

2013年(7)

我的朋友

分类: C/C++

2014-11-25 10:01:08

对于udp而言,recvfrom只返回发送报文的源地址,但是无法知道发送报文的目的地址和收到报文的接口是哪一个?
为了完成这个目的,可以通过setsockopt设置IP_PKTINFO,并使用recvmsg的控制信息来实现。如果支持IP_RECVDSTADDR和IP_RECVIF的话,也可以使用IP_RECVDSTADDR和IP_RECVIF来实现。

size_t recvmsg(int sockfd, struct msghr *msg, int flags);

struct iovec {
    void *iov_base;
    size_t iov_len;
};
struct msghr {
    void *msg_name;
    socklen_t msg_namelen;
   struct iovec *msg_iov;
   size_t msg_iovlen;
   void   *msg_control;
   socklen_t msg_controllen;
   int   msg_flags;
};

udpclient.c

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/socket.h>
  5. #include <sys/types.h>
  6. #include <arpa/inet.h>
  7. #include <string.h>
  8. #define MAXLINE 1024
  9. int main(int argc, char* argv[])
  10. {
  11.     int fd;
  12.     int n;
  13.     struct sockaddr_in server;
  14.     char recv[MAXLINE];
  15.     char send[1024];
  16.     const int optval = 1;
  17.     struct msghdr msg;
  18.     struct iovec iov[1];
  19.     struct cmsghdr *cmptr;
  20.     union {
  21.         struct cmsghdr cm;    //---this ensures alignment --------
  22. #if defined (IP_RECVDSTADDR) && defined (IP_RECVIF)
  23.         char control[CMSG_SPACE(sizeof(struct in_addr))+CMSG_SPACE(sizeof(struct sockaddr_dl))];
  24. #else
  25.         char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
  26. #endif
  27.     } control_u;
  28.     msg.msg_control = control_u.control;
  29.     msg.msg_controllen = sizeof(control_u.control);
  30.     msg.msg_flags = 0;
  31.     
  32.     
  33.     fd = socket(AF_INET,SOCK_DGRAM,0);

  34.     if(fd < 0) {
  35.         printf("socket error\n");
  36.     }

  37. #if defined (IP_RECVDSTADDR) && defined (IP_RECVIF)
  38.     setsockopt(fd,IPPROTO_IP,IP_RECVDSTADDR,&optval,sizeof(optval));
  39.     setsockopt(fd,IPPROTO_IP,IP_RECVIF,&optval,sizeof(optval));
  40. #else
  41.     setsockopt(fd,IPPROTO_IP,IP_PKTINFO,&optval,sizeof(optval));
  42. #endif

  43.     server.sin_family = AF_INET;
  44.     server.sin_port = htons(20000);
  45.     inet_pton(AF_INET,"10.155.3.243",&server.sin_addr);
  46.     
  47.     msg.msg_name = &server;
  48.     msg.msg_namelen = sizeof(struct sockaddr_in);

  49.     iov[0].iov_base = recv;
  50.     iov[1].iov_len = MAXLINE;

  51.     msg.msg_iov = iov;
  52.     msg.msg_iovlen = 1;

  53.     while(fgets(send,1024,stdin)!=NULL)
  54.     {
  55.         sendto(fd,send,strlen(send),0,(struct sockaddr*)&server,sizeof(struct sockaddr));
  56.         //n = recvfrom(fd,recv,1024,0,NULL,NULL);
  57.         n = recvmsg(fd,&msg,0);
  58.         for(cmptr = CMSG_FIRSTHDR(&msg);cmptr;cmptr = CMSG_NXTHDR(&msg,cmptr)) {
  59. #if defined (IP_RECVDSTADDR) && defined (IP_RECVIF)
  60.             if((cmptr->cmsg_level == IPPROTO_IP) && (cmptr->cmsg_type == IP_RECVDSTADDR)){
  61.                 printf("dst ipaddr=%s\n",inet_ntoa(struct in_addr)CMSG_DATA(cmptr));
  62.             }else if((cmptr->cmsg_level == IPPROTO_IP) && (cmptr->cmsg_type == IP_RECVIF)){
  63.                 printf("dst if=%d\n",((struct sockaddr_dl*)CMSG_DATA(cmptr))->sdl_index);
  64.             }
  65. #else
  66.             if((cmptr->cmsg_level == IPPROTO_IP) && (cmptr->cmsg_type == IP_PKTINFO)) {
  67.                 printf("%s,%d\n",inet_ntoa(((struct in_pktinfo*)CMSG_DATA(cmptr))->ipi_spec_dst),((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex);
  68. #endif
  69.             }
  70.         }
  71.         //printf("msg.msg_flags=0x%x\n",msg.msg_flags);
  72.         if(msg.msg_flags & MSG_TRUNC) {
  73.             printf("datagram truncated\n");
  74.         }
  75.         recv[n] = '\0';
  76.         if(n >0)
  77.             fputs(recv,stdout);
  78.     }
  79.     return 0;
  80. }
udpserver.c

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <error.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <arpa/inet.h>
  8. #include <strings.h>

  9. int main(int argc, char *argv[])
  10. {
  11.     struct sockaddr_in server;
  12.     struct sockaddr_in source;
  13.     socklen_t len;
  14.     char recv[1024];
  15.     int fd;
  16.     int n;

  17.     fd = socket(AF_INET,SOCK_DGRAM,0);
  18.     if(fd < 0) {
  19.         printf("socket error\n");
  20.     }
  21.     bzero(&source,sizeof(source));
  22.     bzero(&server,sizeof(server));
  23.     server.sin_family = AF_INET;
  24.     server.sin_port = htons(20000);
  25.     server.sin_addr.s_addr = htonl(INADDR_ANY);

  26.     if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr)) < 0) {
  27.         printf("bind error\n");
  28.         close(fd);
  29.     }
  30.     len = sizeof(source);
  31.     while(1) {
  32.         
  33.         n = recvfrom(fd,recv,1024,0,(struct sockaddr*)&source,&len);

  34.         if(n > 0) {
  35.             sendto(fd,recv,n,0,(struct sockaddr*)&source,len);
  36.         }
  37.     }
  38.     return 0;
  39. }
1.编译服务器:
gcc -g udpserver.c -o udpserver -Wall
2.运行:
./udpserver
3.编译客户端
gcc -g udpclient.c -o udpclient -Wall
4.运行客户端
gwwu@hz-dev2.wgw.com:~/test/socket/udp>./udpclient
gwwu@hz-dev2.wgw.com:~/test/socket/udp>./udpclient
dfads
10.155.3.246,2   //--10.155.3.246即客户端自己的地址,也是服务器发送给客户端的报文中的目的地址,2为目的接口
dfads
dfad
10.155.3.246,2
dfad
dfadf
10.155.3.246,2
dfadf




阅读(1506) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~