单播:

UDP不像TCP,无需在连接状态下交换数据,因此基于UDP的接收方和发送方也无需经过连接过程。也就是说,不必调用listen()和accept()函数。UDP中只有创建套接字的过程和数据交换的过程。不管是服务器端还是客户端都只需要 1 个套接字。Linux 网络传输层UDP_IP

步骤:

1》创建套接字socket

#include <sys/types.h>

#include <sys/socket.h>

int  socket(int  domain,int type, int protocol);

参数:

domain:协议族

AF_INET  IPV4

AF_INET6  IPV6

type:

SOCK_STREAM :

SOCK_DGRAM  :UDP

protocol:固定写0

返回值:

成功返回描述套接字sockfd,失败返回-1

2》接收方的:bind(绑定自己的IP/PORT);

3》UDP发送函数  --  sendto

#include <sys/types.h>

#include <sys/socket.h>

ssize_t    //套接字

 const void *buf,   //要发送的消息的首地址

size_t len,  //消息大小

int flags,  //0

        const struct sockaddr *dest_addr,//接收方的IP和端口

socklen_t addrlen//上一个参数的大小

);

返回值:成功则返回实际传送出去的字符数,失败返回-1;

 

4》UDP接收函数  -- recvfrom

ssize_t recvfrom(int sockfd,  //套接字

 void *buf,   //接收到的内容存放的位置的首地址

size_t len,//接收的大小

int flags,//0

            struct sockaddr *src_addr, //提供空间

socklen_t *addrlen //上一个参数的大小,需要写地址

);

返回值:如果正确接收返回接收到的字节数,失败返回-1

单播例题

//单播发
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#define PORT 11224
#define IP "192.168.31.36"
int main()//单播发
{
    //1.创建套接字
    int fd=socket(AF_INET,SOCK_DGRAM,0);
    if(fd==-1)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in fa_addr;//暂时发到该结构体内
    fa_addr.sin_port=htons(PORT);
    fa_addr.sin_addr.s_addr=inet_addr(IP);
    fa_addr.sin_family=AF_INET;

    //2.发
    int num=0;
    while(1)
    {
        sendto(fd,&num,4,0,(struct sockaddr *)&fa_addr,sizeof(fa_addr));
        num++;
        sleep(1);
    }

   
    
    return 0;
}
//----------单播收
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#define PORT 11224
#define IP "192.168.31.36"
int main()
{
    //1.创建套接字
    int fd=socket(AF_INET,SOCK_DGRAM,0);
    if(fd==-1)
    {
        perror("socket");
        return -1;
    }
    //2.绑定

    struct sockaddr_in du_addr;
    du_addr.sin_port=htons(PORT);
    du_addr.sin_addr.s_addr=inet_addr(IP);
    du_addr.sin_family=AF_INET;
    int res=bind(fd,(struct sockaddr *)&du_addr,sizeof(du_addr));
    if(res==-1)
    {
        perror("bind");
        return -1;
    }
    //3.收
    int num=0;
    struct sockaddr_in o_addr;//用于保存发送端的端口和地址
    socklen_t len = sizeof(o_addr);
    while(1)
    {
        recvfrom(fd,&num,4,0,(struct sockaddr *)&o_addr,&len);
        printf("num=%d\n",num);
    }

   
    
    return 0;
}

广播

udp具有广播功能,即一个发送方,多个接收方;

广播:处于局部网中的所有设备都可以接收到消息 比如:校园广播

广播的地址:网络号不变,主机号为255

Linux 网络传输层UDP_套接字_02

步骤:

1》创建套接字

#include <sys/types.h>

#include <sys/socket.h>

int  socket(int  domain,int  type, int protocol);

参数:

domain:协议族

AF_INET  IPV4

AF_INET6  IPV6

type:

SOCK_STREAM :

SOCK_DGRAM  :UDP

protocol:固定写0

返回值:成功返回描述网络连接套接字sockfd,失败返回-1

 

2》设置套接字,具有广播功能

socket创建的UDP套接字支持组播和广播,但是想要使用广播,必须用setsockopt设置广播的功能

int setsockopt(int sockfd,

int level,

                                       int optname,

const void *optval,

socklen_t optlen

);

函数功能:设置套接字的选项

参数:    sockfd:socket创建的套接字fd

                     level--选项所在的级别:

想让套接字有广播功能,就必须把level设置为SOL_SOCKET

SOL_SOCKET -- 广播功能所在的级别

optname--选项所在的名称:

SO_BROADCAST  (广播功能)

optval: 整数的地址

int num = 1;//开启功能   &num

       0--失能(关闭此功能,系统默认关闭)

       1--使能(开启此功能)  

optlen:optval的大小 //sizeof(num)

3》发送

  IP:网络号不变,主机号为255

  port:和接收方保持一致

4》接收方bind

IP:INADDR_ANY

port:和发送方的sendto里面的port保持一致

 广播例题

//-----------广播发
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#define PORT 11227
#define IP "172.20.10.4"
int main()//发送端
{
    //1.创建套接字
    int fd=socket(AF_INET,SOCK_DGRAM,0);//IPV4 UDP
    if(fd==-1)
    {
        perror("socket");
        return -1;
    }
    //2.套接字设置
    int num=1;//使能,设置套接子具有广播功能
    setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&num,sizeof(num));
    //3.发送
    num=100;
    struct sockaddr_in fa_addr;//发送到此
    fa_addr.sin_family=AF_INET;//IPV4
    fa_addr.sin_port=htons(PORT);
    fa_addr.sin_addr.s_addr=inet_addr(IP);
    while(1)//循环发
    {
        sendto(fd,&num,4,0,(struct sockaddr *)&fa_addr,sizeof(fa_addr));
        sleep(1);
        num++;
    }
    return 0;
}
//-----------广播收
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#define PORT 11227
int main()//广播收
{
    //1.创建套接子
    int fd=socket(AF_INET,SOCK_DGRAM,0);
    if(fd==-1)
    {
        perror("socket");
        return -1;
    }
    //2.绑定
    struct sockaddr_in s_addr;
    s_addr.sin_family=AF_INET;
    s_addr.sin_port=htons(PORT);
    s_addr.sin_addr.s_addr=INADDR_ANY;
    int res=bind(fd,(struct sockaddr *)&s_addr,sizeof(s_addr));
    if(res==-1)
    {
        perror("bind");
        return -1;
    }
    //3.接收
    int num=0;
    struct sockaddr_in cun_addr;//读取的方到该结构体内
    socklen_t len=sizeof(cun_addr);
    while(1)
    {
        recvfrom(fd,&num,4,0,(struct sockaddr *)&cun_addr,&len);
        printf("num:%d\n",num);
    }
    return 0;
}

多播(组播)

对一组特定的主机发送消息 比如:直播,多播(D类),IP地址分为:224.0.0.0~239.255.255.255

步骤:

1》创建套接字 -- socket,创建UDP套接字

fd = socket(AF_INET,SOCK_DGRAM,0);

2》设置组播功能

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

       函数功能:设置套接字的选项

       参数:   

sockfd: socket创建的套接字

                     level: 级别

                            SOL_SOCKET : 广播级别

                            IPPROTO_IP :组播级别 

                     optname: 选项由level决定,level选的是IPPROTO_IP,optname有两种选择

                                   IP_ADD_MEMBERSHIP  加入组播

                                   IP_MULTICAST_IF      创建组播  

                     optval:设置参数 由optname决定

                            当optname为

                                   IP_ADD_MEMBERSHIP(加入组播),optval 是struct ip_mreqn 这个结构体

                                   IP_MULTICAST_IF  (创建组播),optval 也是struct ip_mreqn  这个结构体

                                   struct ip_mreqn

{

                                    struct in_addr imr_multiaddr;//多播组的地址224.0.0.0-239.255.255.255 “224.0.0.2”                                             struct in_addr imr_address;//本地的IP地址,填固定的宏INADDR_ANY即可

                                    int imr_ifindex; //物理硬件地址:可以用物理硬件ID函数:if_nametoindex("ens33"); 其中ens33是网卡的名字,通过名字获取编号

                 };    头文件:#include <net/if.h> 

                     optlen:optval的大小

3》发送

IP:多播组的地址224.0.0.0-239.255.255.255

        选择一个即可  “224.0.0.2”

port:和接收方保持一致

4》接收方bind

IP:INADDR_ANY

port:和发送方的sendto里面的port保持一致

 

TCP例如: 当服务器结束之后,再次运行会出现bind错误(地址被占用) 解决办法: int sockfd = socket(AF_INET,SOCK_STREAM,0);
创建套接字之后,用:
int val = 1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val));
setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,&val,sizeof(val));