3.UDP通信

1.UDP协议的特点:

  不需要链接, 不可靠传输协议,速度快实时性强,传输数据量小。

2.发送数据端实现的步骤如下:

  1. 创建套接字(socket)  SOCK_STREAM--TCP,  SOCK_DGRAM--UDP

  2. 发送数据(sendto)

3.接收数据端的实现步骤如下:

  1. 创建套接字(socket)
  2. 绑定端口地址(bind)
  3. 接收数据(recvfrom)阻塞

  Linux提供的函数接口如下:

发送数据

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
参数:int sockfd套接字描述符, 
      const void *buf,--要发送的数据
      size_t len数据长度
      int flags-标志设置为0
      const struct sockaddr *dest_addr----数据要发送到的地址, 
  socklen_t addrlen---dest_addr长度
返回值:成功发送的字节数, 失败-1

接收数据

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

参数:int sockfd套接字描述符, 
      const void *buf,--要存储接收的数据
      size_t len数据长度--buf空间大小
  socklen_t addrlen---dest_addr长度//地址长度
      int flags-标志设置为0
      struct sockaddr *src_addr;---存储发送方的地址端口
      socklen_t *addrlen----src_addr指针所指向的空间大小

返回值:成功发送的字节数, 失败-1

发送端的实现代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//#include <       
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void)
{
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        perror("socket fail");
        exit(1);
    }
    //2.发送数据到指定的地址端口
    char buffer[128]="hello world";
    struct sockaddr_in toaddr;
    memset(&toaddr, 0, sizeof(toaddr));
    toaddr.sin_family = AF_INET;
    toaddr.sin_port = htons(6666);
    toaddr.sin_addr.s_addr = inet_addr("192.168.1.240");

    size_t size = sendto(sockfd, buffer, strlen(buffer),0, 
            (struct sockaddr*)&toaddr, sizeof(toaddr));
    if(size  != strlen(buffer) )
    {
        perror("sendto fail");
        exit(1);
    }

    return 0;
}

接收端的实现代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//#include <       
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void)
{
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        perror("socket fail");
        exit(1);
    }

    //2.绑定
    struct sockaddr_in toaddr;
    memset(&toaddr, 0, sizeof(toaddr));
    toaddr.sin_family = AF_INET;
    toaddr.sin_port = htons(6666);
    toaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret  = bind(sockfd, (struct sockaddr*)&toaddr, sizeof(toaddr));
    if(ret < 0)
    {
        perror("bind fail");
        exit(1);
    }

    
    //3.接收数据
    char buffer[128]={0};
    struct sockaddr_in saddr;
    socklen_t len = sizeof(saddr);
    size_t size = recvfrom(sockfd, buffer, sizeof(buffer),0, 
            (struct sockaddr*)&saddr,&len);
    if(size  < 0 )
    {
        perror("recvfrom fail");
        exit(1);
    }
    printf("%s
", buffer);
    return 0;
}

2.套接字的设置  setsockopt

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
参数:int sockfd --要设置的套接字
      int level --设置级别选择(SOL_SOCKET, IPPROTO_IP)
      int optname --要与第二参数对应
      const void *optval --根据第三个参数后面的数据类型
socklen_t optlen---第四个参数的空间的大小
返回值:成功0, 失败-1

3.设置端口复用  只有最后绑定端口的那个基础讷航才可以接收到端口的数据

int op = 1;
    int opt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op));
    if(opt < 0)
    {
        perror("setsockopt fail");
        exit(1);
    }

4.UDP实现广播通信

 步骤如下:

  在linux首先要通过setsockopt来开启关闭广播(发送端)

int op = 1;
    int opt = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));

  发送广播的流程:

    (1)创建套接字(SOCK_DGRAM

    (2)开启广播

    (3)发送数据到广播地址(假设是192.168.1.255)

#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>    
#include <netinet/in.h>
#include <arpa/inet.h>
#define BROADCAST_ADDR "192.168.1.255"
#define PORT 6666
int main(void)
{
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        perror("socket fail");
        exit(1);
    }
    //开启广播
    int op =1;
    int ret  = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&op, sizeof(op));
    if(ret < 0)
    {
        perror("开启广播失败");
        exit(1);
    }
    //2.发送数据到指定的地址端口
    char buffer[128]="hello world";
    struct sockaddr_in toaddr;
    memset(&toaddr, 0, sizeof(toaddr));
    toaddr.sin_family = AF_INET;
    toaddr.sin_port = htons(PORT);
    toaddr.sin_addr.s_addr = inet_addr(BROADCAST_ADDR);

    size_t size = sendto(sockfd, buffer, strlen(buffer),0, 
            (struct sockaddr*)&toaddr, sizeof(toaddr));
    if(size  != strlen(buffer) )
    {
        perror("sendto fail");
        exit(1);
    }
    return 0;
}

    数据接收端:

    (4)创建套接字(socket)

    (5)绑定端口地址(bind)

    (6)接收数据(recvfrom)阻塞

5.UDP实现组播

  组播(多播):只有超级用户才有权限发送组播信息  组播地址 224.0.0.0---239.255.255.255

实现步骤:

  发送端:

    (1)     创建udp套接字

    (2)     发送数据到组播地址

  接收端

    (1)     创建udp套接字

    (2)     绑定地址端口

    (3)     加入组播/ 退出组播

      要通过setsockopt设置套接字添加到组播组

struct ip_mreq  {                                                           
     struct in_addr imr_multiaddr;   /* IP multicast address of group */组播地址
     struct in_addr imr_interface;   /* local IP address of interface */本地网卡
} mreq; 
初始化mreq
mreq.imr_multiaddr = 
setsockopt(sockfd, IPPROTO_IP,  IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

    (4)     接收数据

例子:添加组播数组

struct ip_mreq  mreq;
    mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.100");
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

UDP组播发送端的代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//#include <       
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void)
{
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        perror("socket fail");
        exit(1);
    }
    //2.发送数据到指定的地址端口
    char buffer[128]="hello world";
    struct sockaddr_in toaddr;
    memset(&toaddr, 0, sizeof(toaddr));
    toaddr.sin_family = AF_INET;
    toaddr.sin_port = htons(6666);
    toaddr.sin_addr.s_addr = inet_addr("224.0.0.100");

    size_t size = sendto(sockfd, buffer, strlen(buffer),0, 
            (struct sockaddr*)&toaddr, sizeof(toaddr));
    if(size  != strlen(buffer) )
    {
        perror("sendto fail");
        exit(1);
    }

    return 0;
}

接收端的代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//#include <       
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void)
{
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        perror("socket fail");
        exit(1);
    }

    //设置端口复用
    int op = 1;
    int opt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op));
    if(opt < 0)
    {
        perror("setsockopt fail");
        exit(1);
    }


    //2.绑定
    struct sockaddr_in toaddr;
    memset(&toaddr, 0, sizeof(toaddr));
    toaddr.sin_family = AF_INET;
    toaddr.sin_port = htons(6666);
    toaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret  = bind(sockfd, (struct sockaddr*)&toaddr, sizeof(toaddr));
    if(ret < 0)
    {
        perror("bind fail");
        exit(1);
    }

    
    //加入到组播组
    //struct sockaddr_in s;
    //s.sin_addr.s_addr = inet_addr("192.168.1.51";)


    struct ip_mreq  mreq;
    mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.100");
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

    //3.接收数据
    char buffer[128]={0};
    struct sockaddr_in saddr;
    socklen_t len = sizeof(saddr);
    size_t size = recvfrom(sockfd, buffer, sizeof(buffer),0, 
            (struct sockaddr*)&saddr,&len);
    if(size  < 0 )
    {
        perror("recvfrom fail");
        exit(1);
    }

    printf("%s
", buffer);

    return 0;
}

PS:哪里写错了请指正,互相学习。

原文地址:https://www.cnblogs.com/smallqizhang/p/12564471.html