一、UDP

  UDP:是一个支持无连接的传输协议,全称是用户数据包协议(User Datagram Protocol)。UDP协议无需像TCP一样要建立连接后才能发送封装的IP数据报,也是因此UDP相较于TCP效率更高一些,但是由于没有建立连接,UDP只管发送数据,不管数据是否被接收,所以UDP传输数据是不安全的,容易丢包。

  通信流程:

  服务端

    1、创建通信用套接字:socket(AF_INET, SOCK_DGRAM, 0);   和TCP不同之处在于第二个参数改为SOCK_DGRAM。

    2、绑定套接字:bind(...);

    3、通信:接收数据,recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);。发送数据,sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, const socklen_t *addrlen);  第五个参数都是另一端的信息,src_addr是传出参数。

  客户端同服务端。

二、广播

  广播:在IP子网内广播数据包,所有在子网内部的主机都将收到这些数据包。广播的使用范围仅在本地子网中,通过路由器控制广播的传输。广播地址:xxx.xxx.xxx.255。

  通信流程:

    1、创建并绑定套接字,同UDP。

    2、初始化客户端信息,主要是设置客户端ip为广播地址。

    3、开放服务器的广播权限:int flag = 1;   setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));

    4、给客户端(子网内的主机)发送数据。

  客户端同UDP,不能向服务器发送数据。

//server//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h> int main(int argc, const char* argv[])
{
// 创建套接字
int fd = socket(AF_INET, SOCK_DGRAM, );
if(fd == -)
{
perror("socket error");
exit();
} // 绑定server的iP和端口
struct sockaddr_in serv;
memset(&serv, , sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(); // server端口
serv.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv));
if(ret == -)
{
perror("bind error");
exit();
} // 初始化客户端地址信息
struct sockaddr_in client;
memset(&client, , sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(); // 客户端要绑定的端口
// 使用广播地址给客户端发数据
inet_pton(AF_INET, "192.168.123.255", &client.sin_addr.s_addr); // 给服务器开放广播权限
int flag = ;
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag)); // 通信
while()
{
// 一直给客户端发数据
static int num = ;
char buf[] = {};
sprintf(buf, "hello, udp == %d\n", num++);
int ret = sendto(fd, buf, strlen(buf)+, , (struct sockaddr*)&client, sizeof(client));
if(ret == -)
{
perror("sendto error");
break;
} printf("server == send buf: %s\n", buf); sleep();
} close(fd); return ;
}
//client//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h> int main(int argc, const char* argv[])
{
int fd = socket(AF_INET, SOCK_DGRAM, );
if(fd == -)
{
perror("socket error");
exit();
} // 绑定iP和端口
struct sockaddr_in client;
memset(&client, , sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons();
inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
int ret = bind(fd, (struct sockaddr*)&client, sizeof(client));
if(ret == -)
{
perror("bind error");
exit();
} // 接收数据
while()
{
char buf[] = {};
int len = recvfrom(fd, buf, sizeof(buf), , NULL, NULL);
if(len == -)
{
perror("recvfrom error");
break;
} printf("client == recv buf: %s\n", buf);
} close(fd); return ;
}

三、组播

  组播:在发送者和每一接收者之间实现点对多点网络连接。如果一台发送者同时给多个接收者传输相同的数据,也只需复制一份相同的数据包。它提高了数据传送效率,减少了骨干网络出现拥塞的可能性。组播不同于广播的地方在于其不局限于局域网,而且其效率比广播更高。

  组播地址:224.0.0.0~224.0.0.255,预留组播地址(永久组地址),224.0.0.0保留不做分配,其它地址供路由器协议使用。224.0.1.0~224.0.1.255,公用组播地址,可以用于Internet,需要申请。224.0.2.0~238.255.255.255,用户可用组播地址(临时组地址),全网有效。239.0.0.0~239.255.255.255,本地管理组播地址, 仅在特定的本地范围内有效。

  通信流程:

    1、创建并绑定套接字,同UDP。

    2、初始化客户端地址信息,设置组播地址和客户端要绑定的端口。

    3、开放组播权限

// 给服务器开放组播权限
struct ip_mreqn flag;
// init flag
inet_pton(AF_INET, "239.0.0.10", &flag.imr_multiaddr.s_addr); // 组播地址
inet_pton(AF_INET, "0.0.0.0", &flag.imr_address.s_addr); // 本地IP
flag.imr_ifindex = if_nametoindex("ens33");
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &flag, sizeof(flag));

    客户端,绑定端口要与服务端设置的相一致

    客户端加入到组播地址

// 加入到组播地址
struct ip_mreqn fl;
inet_pton(AF_INET, "239.0.0.10", &fl.imr_multiaddr.s_addr);
inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr);
fl.imr_ifindex = if_nametoindex("ens33");
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl));
//server//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h> int main(int argc, const char* argv[])
{
// 创建套接字
int fd = socket(AF_INET, SOCK_DGRAM, );
if(fd == -)
{
perror("socket error");
exit();
} // 绑定server的iP和端口
struct sockaddr_in serv;
memset(&serv, , sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(); // server端口
serv.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv));
if(ret == -)
{
perror("bind error");
exit();
} // 初始化客户端地址信息
struct sockaddr_in client;
memset(&client, , sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(); // 客户端要绑定的端口
// 使用组播地址给客户端发数据
inet_pton(AF_INET, "239.0.0.10", &client.sin_addr.s_addr); // 给服务器开放组播权限
struct ip_mreqn flag;
// init flag
inet_pton(AF_INET, "239.0.0.10", &flag.imr_multiaddr.s_addr); // 组播地址
inet_pton(AF_INET, "0.0.0.0", &flag.imr_address.s_addr); // 本地IP
flag.imr_ifindex = if_nametoindex("ens33");
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &flag, sizeof(flag)); // 通信
while()
{
// 一直给客户端发数据
static int num = ;
char buf[] = {};
sprintf(buf, "hello, udp == %d\n", num++);
int ret = sendto(fd, buf, strlen(buf)+, , (struct sockaddr*)&client, sizeof(client));
if(ret == -)
{
perror("sendto error");
break;
} printf("server == send buf: %s\n", buf); sleep();
} close(fd); return ;
}
//client//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h> int main(int argc, const char* argv[])
{
int fd = socket(AF_INET, SOCK_DGRAM, );
if(fd == -)
{
perror("socket error");
exit();
} // 绑定iP和端口
struct sockaddr_in client;
memset(&client, , sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(); // ........
inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
int ret = bind(fd, (struct sockaddr*)&client, sizeof(client));
if(ret == -)
{
perror("bind error");
exit();
} // 加入到组播地址
struct ip_mreqn fl;
inet_pton(AF_INET, "239.0.0.10", &fl.imr_multiaddr.s_addr);
inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr);
fl.imr_ifindex = if_nametoindex("ens33");
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl)); // 接收数据
while()
{
char buf[] = {};
int len = recvfrom(fd, buf, sizeof(buf), , NULL, NULL);
if(len == -)
{
perror("recvfrom error");
break;
} printf("client == recv buf: %s\n", buf);
} close(fd); return ;
}

Linux网络编程四、UDP,广播和组播的更多相关文章

  1. linux网络编程之二-----多播(组播)编程

    多播编程实例 服务器端 下面是一个多播服务器的例子.多播服务器的程序设计很简单,建立一个数据包套接字,选定多播的IP地址和端口,直接向此多播地址发送数据就可以了.多播服务器的程序设计,不需要服务器加入 ...

  2. Linux网络编程(四)

    在linux网络编程[1-3]中,我们编写的网络程序仅仅是为了了解网络编程的基本步骤,实际应用当中的网络程序并不会用那样的.首先,如果服务器需要处理高并发访问,通常不会使用linux网络编程(三)中那 ...

  3. Linux网络编程:UDP Socket编程范例

    TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...

  4. Linux 网络编程四(socket多线程升级版)

    //网络编程--客户端 #include <stdio.h> #include <stdlib.h> #include <string.h> #include &l ...

  5. python网络编程(UDP+广播)

    UDP广播案例,一端发送,多端接受: 发送端: # UDP广播案例 from socket import * from time import sleep # 设定目标地址 dest=('176.21 ...

  6. UDP广播,组播服务器

    广播 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ ...

  7. Linux网络编程:UDP实现可靠的文件传输

    我们知道,用TCP实现文件传输很简单.相对于TCP,因为UDP是面向无连接.不可靠的传输协议,所以我们需要考虑丢包和后发先至(包的顺序)的问题,所以我们想要实现UDP传输文件,则需要解决这两个问题.方 ...

  8. linux网络编程笔记——UDP

    目前这部分代码会出现阻塞问题,暂时尚未解决 #include "udp.h" #include <stdio.h> #include <string.h> ...

  9. Linux 网络编程(UDP)

    客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...

随机推荐

  1. English-培训3-Please call me Beth

  2. 【日语】日语能力考试N2级核心词汇必备—接续词

    日语能力考试N2级核心词汇必备—接续词 顺接 だから 因为......所以......(下文可用命令,意志劝诱等)その結果  其结果(口语,书面语都行,但是比较生硬)したがって  从而,因而(书面语, ...

  3. Linux日志查看

    Linux日志查看: 1.Last -a 把从何处登入系统的主机名称或IP地址,显示在最后一行.-d 指定记录文件.指定记录文件.将IP地址转换成主机名称.-f <记录文件>  指定记录文 ...

  4. 张量(tensor)的广播

    在使用numpy 对张量(数组)进行操作时,两个形状相同的张量进行加减等运算很容易理解,那么不同形状的张量之间的运算是通过广播来实现的.广播实际上很简单,但是弄清楚是也花了不小功夫,这里记录一下. 广 ...

  5. Vue学习官网和Vue的书籍 目录结构

    Vue基础知识学习网站[中文] https://cn.vuejs.org/v2/guide/ Vue路由知识学习网站[中文] https://router.vuejs.org/zh/guide/  V ...

  6. java基本数据类型包装

    1. 2. 左边的是对象,自动装箱为对象,右边的是基本的数据类型. 3. 如果m,n换成128就超出范围,结果就不一样. 是因为把在这区间内的值都放在了常量池里面. Integer m = Integ ...

  7. Devices Tree加载流程

    DT.IMG布局 hdr zImage Ramdisk.img DT.img 其中DT.img由DTBTOOL打包所有编译生成的dtb生成:布局如下: DT header dt_entry_0 dt_ ...

  8. 【DRF框架】序列化组件——字段验证

    单个字段的验证 1.在序列化器里定义校验字段的钩子方法   validate_字段 2.获取字段的数据 3.验证不通过,抛出异常  raise serializers.ValidationError( ...

  9. 如何在CentOS上搭建gitlab服务器

    步骤 1. 打开HTTP和SSH访问 1.1 安装 sudo yum install -y curl policycoreutils-python openssh-server 1.2 开启SSH 这 ...

  10. 2019-ACM-ICPC-南京区网络赛-D. Robots-DAG图上概率动态规划

    2019-ACM-ICPC-南京区网络赛-D. Robots-DAG图上概率动态规划 [Problem Description] ​ 有向无环图中,有个机器人从\(1\)号节点出发,每天等概率的走到下 ...