Linux网络编程四、UDP,广播和组播
一、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,广播和组播的更多相关文章
- linux网络编程之二-----多播(组播)编程
多播编程实例 服务器端 下面是一个多播服务器的例子.多播服务器的程序设计很简单,建立一个数据包套接字,选定多播的IP地址和端口,直接向此多播地址发送数据就可以了.多播服务器的程序设计,不需要服务器加入 ...
- Linux网络编程(四)
在linux网络编程[1-3]中,我们编写的网络程序仅仅是为了了解网络编程的基本步骤,实际应用当中的网络程序并不会用那样的.首先,如果服务器需要处理高并发访问,通常不会使用linux网络编程(三)中那 ...
- Linux网络编程:UDP Socket编程范例
TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...
- Linux 网络编程四(socket多线程升级版)
//网络编程--客户端 #include <stdio.h> #include <stdlib.h> #include <string.h> #include &l ...
- python网络编程(UDP+广播)
UDP广播案例,一端发送,多端接受: 发送端: # UDP广播案例 from socket import * from time import sleep # 设定目标地址 dest=('176.21 ...
- UDP广播,组播服务器
广播 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ ...
- Linux网络编程:UDP实现可靠的文件传输
我们知道,用TCP实现文件传输很简单.相对于TCP,因为UDP是面向无连接.不可靠的传输协议,所以我们需要考虑丢包和后发先至(包的顺序)的问题,所以我们想要实现UDP传输文件,则需要解决这两个问题.方 ...
- linux网络编程笔记——UDP
目前这部分代码会出现阻塞问题,暂时尚未解决 #include "udp.h" #include <stdio.h> #include <string.h> ...
- Linux 网络编程(UDP)
客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...
随机推荐
- 【es6】promise
一.什么是promise?我们用promise解决什么样的问题 promise是异步编程的一种解决方案:从语法上来说,Promise是一个对象,从他可以获取异步操作的信息:从本意上讲,它是承诺,它承诺 ...
- MySQL 乱码问题解决
修改 配置文件 只需留下 my.ini文件,然后修改其编码配置. 配置如下 # Example MySQL config file for large systems. # # This is for ...
- Eva 剧情解析
Eva 剧情解析 来源 https://zhuanlan.zhihu.com/p/20864898 [0.写在前面的话] 相信和我年龄差不多的小伙伴们对<新世纪福音战士>( <Neo ...
- JavaScript 基础(数据类型、函数、流程控制、对象)
一.JavaScript概述 1.1 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名Script ...
- 开源项目hutool之zip_slip漏洞
今天突然看到了去年写的一篇漏洞分析文章,搬到博客上 ---------------- Hutool是Github上的一个开源项目,是一个java的工具包,对文件.流.加密解密.转码.正则.线程.XML ...
- 时间都去哪儿了?开源一个统计iPhone上App运行时间和打开次数的小工具【iOS8已失效】
如今,大家每天都有大量时间花在手机上,但是,大家有没有想过自己的时间都花在哪些App上了呢?相信很多人都有这样的需求,不过iOS系统本身并不能显示每个App的运行时间和次数,因此,本人写了这样一个小工 ...
- 解决 google 浏览器记住密码导致输入框样式改变(变成淡黄色背景)
直接在页面上使用css代码: input:-webkit-autofill , textarea:-webkit-autofill, select:-webkit-autofill { -webkit ...
- 父类调用子类的常量 lumen查询数据库方式
我要在一个基类里面实例化所有的model 要根据集成的对象定义的model实例化 BaseRepository.php <?php namespace App\Repository; class ...
- Hadoop安装-单机-伪分布式简单部署配置
最近在搞大数据项目支持所以有时间写下hadoop随笔吧. 环境介绍: Linux: centos7 jdk:java version "1.8.0_181 hadoop:hadoop-3.2 ...
- 在Linux中安装适用于arm64位的nodejs
# 安装适用于arm64位的nodejs runtime v10.16.3 mkdir /runtimes cd /runtimes wget https://nodejs.org/dist/v10. ...