【linux高级程序设计】(第十五章)UDP网络编程应用 3

UDP组播通信

组播IP地址: D类IP地址  1110.**********  224.0.0.1 ~ 239.255.255.255

组播MAC地址:低23位,直接对应IP地址, 从右数第24位为0, 前24位为 01:00:5E

 

最终数据帧如图

 

局域网所有主机网卡都会收到这一消息,但是只有加入到组内的主机才接受该数据包。组播不影响同一局域网内其他主机的效率

 

将自己的主机IP地址加入到组播地址组:

setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq));

第四个参数的类型如下:

struct ip_mreqn
{
    struct in_addr imr_multiaddr;   //组播地址
    struct in_addr imr_address;     //自己IP地址
};

加入相应的组后,即可接收对应组播地址的数据包了

 

 

例子:

发送端:发送组播消息 绑定了自己的ip  没有加入组 只是说发送到某个组

接收端:加入了正确的组,则可以接收到;没有加入相应的组,则不能接收到

用到了新的函数

gethostbyname

#include<netdb.h>
struct hostent* gethostbyname(const char* hostname);

返回值类型

struct hostent{
  char * h_name;
  char ** h_aliases;
  short h_addrtype;
  short h_length;
  char ** h_addr_list;
};
#define h_addr h_addr_list[0]

bcopy

 void bcopy(const void *src, void *dest, int n);

 

发送端代码:

#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFLEN 255

int main(int argc, char **argv)
{
    struct sockaddr_in peeraddr, myaddr;
    int sockfd;
    char recmsg[BUFLEN + 1];
    unsigned int socklen;
    //以UDP方式创建SOCKET对象
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        printf("socket creating error\n");
        exit(EXIT_FAILURE);
    }
    socklen = sizeof(struct sockaddr_in);
    memset(&peeraddr, 0, socklen);
    peeraddr.sin_family = AF_INET;
    peeraddr.sin_port = htons(7838); 
    if(argv[1])      //参数1 获取组播地址
    {
        if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0)
        {
            printf("wrong group address!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("no group address!\n");
        exit(EXIT_FAILURE);
    }
    memset(&myaddr, 0, socklen);
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(23456);
    if(argv[2])    //参数2  读取本机绑定的IP地址
    {
        if(inet_pton(AF_INET, argv[2], &myaddr.sin_addr) <= 0)
        {
            printf("self ip address error!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        myaddr.sin_addr.s_addr = INADDR_ANY;
    }
    //绑定
    if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) == -1)
    {
        printf("Bind error\n");
        exit(EXIT_FAILURE);
    }
    while(1)
    {
        bzero(recmsg, BUFLEN + 1);
        printf("input message to send:");
        if(fgets(recmsg, BUFLEN, stdin) == (char *)EOF)
            exit(EXIT_FAILURE);
        //发送给组播组内主机
        if(sendto(sockfd, recmsg, strlen(recmsg), 0, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < 0)
        {
            printf("sendto error\n");
            exit(EXIT_FAILURE);
        }
        printf("send message:%s\n", recmsg);
    }
}

接收端代码

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netinet/tcp.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/time.h>
#include<netdb.h>
#define BUFLEN 255

int main(int argc, char **argv)
{
    struct sockaddr_in peeraddr;
    struct in_addr ia;
    int sockfd;
    char recmsg[BUFLEN + 1];
    unsigned int socklen, n;
    struct hostent *group;
    struct ip_mreq mreq;
    //创建socket UDP
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);  //创建UDP方式的socket
    if(sockfd < 0)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    bzero(&mreq, sizeof(struct ip_mreq));
    //从参数1获取组播地址
    if(argv[1])
    {
        if((group = gethostbyname(argv[1])) == (struct hostent *)0)  //??
        {
            perror("gethostbyname");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("please input a group address: 224.0.0.1 ~ 239.255.255.255\n");
        exit(EXIT_FAILURE);
    }
    bcopy((void *)group->h_addr, (void *)&ia, group->h_length);  //??
    bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr)); //??
    //从参数2中读取本机IP地址
    if(argv[2])
    {
        if(inet_pton(AF_INET, argv[2], &mreq.imr_interface.s_addr) <= 0)
        {
            printf("Wrong dest IP address!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("Wrong dest IP address!\n");
        exit(EXIT_FAILURE);
    }
    
    //设置客户端加入到组
    if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1)
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    //
    socklen = sizeof(struct sockaddr_in);
    memset(&peeraddr, 0, socklen);
    peeraddr.sin_family = AF_INET;
    peeraddr.sin_port = htons(7838); 
    if(argv[1])      //参数1 获取组播地址
    {
        if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0)
        {
            printf("wrong group address!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("no group address!\n");
        exit(EXIT_FAILURE);
    }
    //绑定
    if(bind(sockfd, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) == -1)
    {
        printf("Bind error\n");
        exit(EXIT_FAILURE);
    }
    while(1)
    {
        bzero(recmsg, BUFLEN + 1);
        n = recvfrom(sockfd, recmsg, BUFLEN, 0, (struct sockaddr *)&peeraddr, &socklen);
        if(n < 0)
        {
            printf("recvfrom err in udptalk!\n");
            exit(EXIT_FAILURE);
        }
        else
        {
            recmsg[n] = 0;
            printf("peer:%s\n", recmsg);
        }
    }
}

posted @ 2015-08-06 15:39  匡子语  阅读(337)  评论(1)    收藏  举报