对于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
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <arpa/inet.h>
-
#include <string.h>
-
#define MAXLINE 1024
-
int main(int argc, char* argv[])
-
{
-
int fd;
-
int n;
-
struct sockaddr_in server;
-
char recv[MAXLINE];
-
char send[1024];
-
const int optval = 1;
-
struct msghdr msg;
-
struct iovec iov[1];
-
struct cmsghdr *cmptr;
-
union {
-
struct cmsghdr cm; //---this ensures alignment --------
-
#if defined (IP_RECVDSTADDR) && defined (IP_RECVIF)
-
char control[CMSG_SPACE(sizeof(struct in_addr))+CMSG_SPACE(sizeof(struct sockaddr_dl))];
-
#else
-
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
-
#endif
-
} control_u;
-
msg.msg_control = control_u.control;
-
msg.msg_controllen = sizeof(control_u.control);
-
msg.msg_flags = 0;
-
-
-
fd = socket(AF_INET,SOCK_DGRAM,0);
-
-
if(fd < 0) {
-
printf("socket error\n");
-
}
-
-
#if defined (IP_RECVDSTADDR) && defined (IP_RECVIF)
-
setsockopt(fd,IPPROTO_IP,IP_RECVDSTADDR,&optval,sizeof(optval));
-
setsockopt(fd,IPPROTO_IP,IP_RECVIF,&optval,sizeof(optval));
-
#else
-
setsockopt(fd,IPPROTO_IP,IP_PKTINFO,&optval,sizeof(optval));
-
#endif
-
-
server.sin_family = AF_INET;
-
server.sin_port = htons(20000);
-
inet_pton(AF_INET,"10.155.3.243",&server.sin_addr);
-
-
msg.msg_name = &server;
-
msg.msg_namelen = sizeof(struct sockaddr_in);
-
-
iov[0].iov_base = recv;
-
iov[1].iov_len = MAXLINE;
-
-
msg.msg_iov = iov;
-
msg.msg_iovlen = 1;
-
-
while(fgets(send,1024,stdin)!=NULL)
-
{
-
sendto(fd,send,strlen(send),0,(struct sockaddr*)&server,sizeof(struct sockaddr));
-
//n = recvfrom(fd,recv,1024,0,NULL,NULL);
-
n = recvmsg(fd,&msg,0);
-
for(cmptr = CMSG_FIRSTHDR(&msg);cmptr;cmptr = CMSG_NXTHDR(&msg,cmptr)) {
-
#if defined (IP_RECVDSTADDR) && defined (IP_RECVIF)
-
if((cmptr->cmsg_level == IPPROTO_IP) && (cmptr->cmsg_type == IP_RECVDSTADDR)){
-
printf("dst ipaddr=%s\n",inet_ntoa(struct in_addr)CMSG_DATA(cmptr));
-
}else if((cmptr->cmsg_level == IPPROTO_IP) && (cmptr->cmsg_type == IP_RECVIF)){
-
printf("dst if=%d\n",((struct sockaddr_dl*)CMSG_DATA(cmptr))->sdl_index);
-
}
-
#else
-
if((cmptr->cmsg_level == IPPROTO_IP) && (cmptr->cmsg_type == IP_PKTINFO)) {
-
printf("%s,%d\n",inet_ntoa(((struct in_pktinfo*)CMSG_DATA(cmptr))->ipi_spec_dst),((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex);
-
#endif
-
}
-
}
-
//printf("msg.msg_flags=0x%x\n",msg.msg_flags);
-
if(msg.msg_flags & MSG_TRUNC) {
-
printf("datagram truncated\n");
-
}
-
recv[n] = '\0';
-
if(n >0)
-
fputs(recv,stdout);
-
}
-
return 0;
-
}
udpserver.c
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <error.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <arpa/inet.h>
-
#include <strings.h>
-
-
int main(int argc, char *argv[])
-
{
-
struct sockaddr_in server;
-
struct sockaddr_in source;
-
socklen_t len;
-
char recv[1024];
-
int fd;
-
int n;
-
-
fd = socket(AF_INET,SOCK_DGRAM,0);
-
if(fd < 0) {
-
printf("socket error\n");
-
}
-
bzero(&source,sizeof(source));
-
bzero(&server,sizeof(server));
-
server.sin_family = AF_INET;
-
server.sin_port = htons(20000);
-
server.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr)) < 0) {
-
printf("bind error\n");
-
close(fd);
-
}
-
len = sizeof(source);
-
while(1) {
-
-
n = recvfrom(fd,recv,1024,0,(struct sockaddr*)&source,&len);
-
-
if(n > 0) {
-
sendto(fd,recv,n,0,(struct sockaddr*)&source,len);
-
}
-
}
-
return 0;
-
}
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
阅读(5025) | 评论(0) | 转发(2) |