cc++:UDP(udp通信、广播、组播),本地套接字

cc++:UDP(udp通信、广播、组播),本地套接字

2023年7月15日发(作者:)

cc++:UDP(udp通信、⼴播、组播),本地套接字⽬录

1. udp

1.1 udp通信流程- 服务器端 - 1.创建通信的套接字 - int fd = socket( af_inet, SOCK_DGRAM, 0) - 2. 绑定 -> 通信的fd 和本地 IP / port 绑定 - struct sockaddr_in addr; - 3.通信 - 接收数据: recvfrom - 发送数据: sendto - 4.关闭通信的fd - close(fd); - 客户端 - 1.创建⼀个通信的套接字 - 2.通信 - 接收数据: recvfrom - 发送数据: sendto - 3.关闭通信的⽂件描述符 - close(); 1.2 操作函数send、sendto1718#include #include

#include //也可以只⽤这⼀个头⽂件,包含了上⾯2个头⽂件

// tcp 发送数据的函数 write ssize_t send(int sockfd, const void *buf, size_t len, int flags);

// udp 发送数据 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 参数: - sockfd: 通信的fd - buf: 要发送的数据 - len: 要发送的数据的长度 - flags: 0 - dest_addr: 通信的另外⼀端的地址信息 - addrlen: dest_addr的内存⼤⼩

recv、recvfrom17181920#include #include

#include //也可以只⽤这⼀个头⽂件,包含了上⾯2个头⽂件

// tcp 接收数据 read ssize_t recv(int sockfd, void *buf, size_t len, int flags);

// udp 接收数据函数 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 参数: - sockfd: 通信的fd - buf: 接收数据的⼀块内存 - len: 接收数据的内存(第⼆个参数)⼤⼩ - flags: 0 - src_addr: 接收谁的数据, 就写⼊了那个终端的地址信息, 如果不要这部分数据 -> NULL - addrlen: src_addr参数对应内存⼤⼩(传⼊传出参数)

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

2. ⼴播向⼦⽹中多台计算机发送消息,并且⼦⽹中所有的计算机都可以接收到发送⽅发送的消息。

只能在局域⽹中使⽤客户端只要绑定了服务器⼴播使⽤的端⼝, 就可以接收到⼴播数据 2.1 ⼴播通信流程服务器端 -> ⼴播的⼀端:

- 创建通信的套接字 int fd = socket( af_inet, SOCK_DGRAM, 0);- 设置udp⼴播属性 setsockopt();- 通信 -> 发送⼴播数据 struct sockaddr_in cliaddr; _port(8888); // ⼴播数据发送到客户端的8888端⼝, 客户端需要绑定该端⼝ _addr.s_addr -> 初始化⼀个⼴播地址 发送数据: sendto(fd, buf, len, 0, &cliaddr, len);- 关闭通信的fd close(fd);客户端- 创建⼀个通信的套接字 int fd = socket( af_inet, SOCK_DGRAM, 0);- 如果想接收⼴播数据, 需要绑定以固定端⼝(服务器⼴播数据使⽤的端⼝) struct sockaddr_in cliaddr; _port(8888);

bind(fd, cliaddr, len);- 通信 接收数据: recvfrom- 关闭通信的⽂件描述符 close();

2.2 设置⼴播属性函数:setsockopt这个函数有许多功能,这⾥只讨论设置⼴播属性函数功能12345678#include int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen); 参数: - sockfd: ⽂件描述符 - level: SOL_SOCKET - optname: SO_BROADCAST - optval: int数值为1, 允许⼴播 - optlen: optval内存⼤⼩

2.3 ⼴播代码服务器:82936373839404142#include #include #include #include #include

int main(){ // 1. 创建通信的套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket"); exit(0); } // 设置⼴播属性 int op = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op)); // 将数据发送给客户端, 使⽤⼴播地址和固定端⼝ // 初始化客户端的地址信息 struct sockaddr_in cliaddr; _family = AF_INET; _port = htons(8989); // 客户端也需要绑定这端⼝ inet_pton(AF_INET, "192.168.247.255", &_addr.s_addr);

int num = 0; // 3. 通信 while(1) { // 接收数据 char buf[128]; // 发送数据 sprintf(buf, "hello, %dn ", num++); sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr)); printf("⼴播的数据: %sn", buf); sleep(1); }

close(fd);

return 0;}客户端:82936373839404142#include #include #include #include #include

int main(){ // 1. 创建通信的套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket"); exit(0); }

// 2. 通信的fd绑定本地的IP和端⼝ struct sockaddr_in addr; _family = AF_INET; _port = htons(8989); _addr.s_addr = INADDR_ANY; int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); if(ret == -1) { perror("bind"); exit(0); } //inet_pton(AF_INET, "0.0.0.0", &_addr.s_addr);

// 3. 通信 while(1) { // 接收数据 char buf[128]; recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL); printf("server say: %sn", buf); }

close(fd);

return 0;}

3 组播⼴播:⽆论连接到局域⽹的客户端想不想接收该数据,Server都会给客户端发送该数据。进⽽造成客户端上数据的拥塞,因此引出了组播:Server可以将数据包只发送给指定组内的客户端,⽽不发送给指定组外的客户端。

特点:1. 可以在internet中进⾏组播2. 加⼊到⼴播的组织中才可以收到数据 3.1 组播地址IP 组播通信必须依赖于 IP 组播地址,在 IPv4 中它的范围从 `224.0.0.0` 到 `239.255.255.255`,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:

3.2 组播通信流程服务器端 -> 播的⼀端:

- 1.创建通信的套接字 int fd = socket( af_inet, SOCK_DGRAM, 0); - 设置udp组播属性 setsockopt();- 2.通信 -> 发送组播数据 struct sockaddr_in cliaddr; _port(8888); // ⼴播数据发送到客户端的8888端⼝, 客户端需要绑定该端⼝ _addr.s_addr -> 初始化⼀个组播地址 发送数据: sendto(fd, buf, len, 0, &cliaddr, len);- 3.关闭通信的fd close(fd);客户端- 1.创建⼀个通信的套接字 int fd = socket( af_inet, SOCK_DGRAM, 0);- 2.如果想接收组播数据, 需要绑定以固定端⼝(服务器组播数据使⽤的端⼝) struct sockaddr_in cliaddr; _port(8888);

bind(fd, cliaddr, len);- 3.客户端加⼊到组播⽹络中 setsockopt():- 4.通信 接收数据: recvfrom- 5.关闭通信的⽂件描述符 close();

3.3 设置组播属性函数:setsockopt这个函数有许多功能,这⾥只讨论设置组播属性函数功能1718192 int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

// 服务器端 -> 进程组播 参数:

- sockfd: 通信的⽂件描述符 - level: IPPROTO_IP - optname: IP_MULTICAST_IF - optval: struct in_addr - optlen: optval 的内存⼤⼩ // 客户端 -> 加⼊到多播组 参数: - sockfd: 通信的⽂件描述符 - level: IPPROTO_IP - optname: IP_ADD_MEMBERSHIP - optval: struct ip_mreqn - optlen: optval 的内存⼤⼩

struct ip_mreqn { // 组播组的IP地址. struct in_addr imr_multiaddr;

// 本地某⼀⽹络设备接⼝的IP地址。 struct in_addr imr_address;

int imr_ifindex; // ⽹卡编号 };

3.4 组播代码服务器:829363738394041424344#include #include #include #include #include

int main(){ // 1. 创建通信的套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket"); exit(0); }

// 设置组播属性 struct in_addr imr_multiaddr;

// 初始化组播地址 inet_pton(AF_INET, "239.0.0.10", &imr_multiaddr.s_addr); setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &imr_multiaddr, sizeof(imr_multiaddr));

// 将数据发送给客户端, 使⽤⼴播地址和固定端⼝ // 初始化客户端的地址信息 struct sockaddr_in cliaddr; _family = AF_INET; _port = htons(8989); // 客户端也需要绑定这端⼝ inet_pton(AF_INET, "239.0.0.10", &_addr.s_addr);

int num = 0; // 3. 通信 while(1) { // 接收数据 char buf[128]; // 发送数据 sprintf(buf, "hello, %dn ", num++); sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr)); printf("组播的数据: %sn", buf); sleep(1); } close(fd); return 0;}客户端:829363738394647#include #include #include #include #include #include

int main(){ // 1. 创建通信的套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket"); exit(0); }

// 2. 通信的fd绑定本地的IP和端⼝ struct sockaddr_in addr; _family = AF_INET; _port = htons(8989); _addr.s_addr = INADDR_ANY; int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); if(ret == -1) { perror("bind"); exit(0); } //inet_pton(AF_INET, "0.0.0.0", &_addr.s_addr); // 加⼊到组播 struct ip_mreqn op; _address.s_addr = INADDR_ANY; // 本地地址 inet_pton(AF_INET, "239.0.0.10", &_multiaddr.s_addr); _ifindex = if_nametoindex("ens33");

setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &op, sizeof(op)); // 3. 通信 while(1) { // 接收数据 char buf[128]; recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL); printf("server say: %sn", buf); } close(fd); return 0;}

4. 本地套接字本地套接字⽤于进程间通信,有没有⾎缘关系都可以。通信流程 -> ⼀般按照tcp流程处理 4.1 结构体sockaddr_un

结构体 sockaddr、sockaddr_in⽤于⽹络通信结构体 sockaddr_un⽤于进程间通信结构体 sockaddr_in⽤于ipv6通信由于结构体sockaddr需要⽤指针偏移添加IP地址,这样很⿇烦,在⽹络通信中我们使⽤sockaddr_in来添加端⼝号、IP地址。再强转成sockaddr类型,因为这2个结构体⼤⼩⼀样,后⾯的服务器—客户端程序会有具体体现。在进程间通信中,使⽤sockaddr_un123456789#include

#define UNIX_PATH_MAX 108

struct sockaddr_un

{ sa_family_t sun_family; // 地址族协议 af_local char sun_path[UNIX_PATH_MAX]; // 套接字⽂件的路径, 这是⼀个伪⽂件, ⼤⼩永远=0};

4.2 本地套接字—进程间通信流程进程1:服务器端1. 创建监听的套接字 int lfd = socket(af_local, sock_stream, 0); 第⼀个参数: AF_UNIX, AF_LOCAL2. 监听的套接字绑定本地的 套接字⽂件-> server端 struct sockaddr_un addr; // 绑定成功之后, 指定的sun_path中的套接字⽂件会⾃动⽣成 bind(lfd, addr, len);3. 监听 listen(lfd, 100);4. 等待并接受连接请求 struct sockaddr_un cliaddr; int connfd = accept(lfd, cliaddr, len);5. 通信 接收数据: read/recv 发送数据: write/send6. 关闭连接 close();进程2:客户端 1. 创建通信的套接字 int fd = socket(af_local, sock_stream, 0); 2. 监听的套接字绑定本地的IP 端⼝ struct sockaddr_un addr; // 绑定成功之后, 指定的sun_path中的套接字⽂件会⾃动⽣成 bind(fd, addr, len); 3. 连接服务器 struct sockaddr_un serveraddr; connect(fd, serveraddr, sizeof(serveraddr)); 4. 通信 接收数据: read/recv 发送数据: write/send 5. 关闭连接 close();

4.3 本地套接字—进程间通代码进程1:服务器1#include 82936373839464748495657585966#include #include #include #include #include #include

int main(){ unlink(""); // 1. 创建监听的套接字 int lfd = socket(AF_LOCAL, SOCK_STREAM, 0); if(lfd == -1) { perror("socket"); exit(0); }

// 2. 绑定本地套接字⽂件 struct sockaddr_un addr; _family = AF_LOCAL; strcpy(_path, ""); //套接字⽂件是伪⽂件,会⾃动⽣成,名字后缀随便取 int ret = bind(lfd, (struct sockaddr*)&addr, sizeof(addr)); if(ret == -1) { perror("bind"); exit(0); }

// 3. 监听 ret = listen(lfd, 100); if(ret == -1) { perror("listen"); exit(0); }

// 4. 等待并接受连接请求 struct sockaddr_un cliaddr; int len = sizeof(cliaddr); int connfd = accept(lfd, (struct sockaddr*)&cliaddr, &len); if(connfd == -1) { perror("accept"); exit(0); } printf("client socket fileName: %sn", _path);

// 5. 通信 while(1) { // 接收数据 char buf[128]; int nums = recv(connfd, buf, sizeof(buf), 0); if(nums == -1) { perror("recv"); exit(0); } else if(nums == 0) { printf(""); break; } else {666768697071727374 { printf("client say: %sn", buf); send(connfd, buf, nums, 0); } } close(connfd); close(lfd); return 0;}进程2:客户端8293637383946474849505152#include #include #include #include #include #include

int main(){ unlink(""); // 1. 创建通信的套接字 int cfd = socket(AF_LOCAL, SOCK_STREAM, 0); if(cfd == -1) { perror("socket"); exit(0); }

// 2. 绑定本地套接字⽂件 struct sockaddr_un addr; _family = AF_LOCAL; strcpy(_path, ""); // 绑定成功, 会⾃动⽣成 int ret = bind(cfd, (struct sockaddr*)&addr, sizeof(addr)); if(ret == -1) { perror("bind"); exit(0); }

// 3. 连接服务器 struct sockaddr_un seraddr; _family = AF_LOCAL; strcpy(_path, ""); ret = connect(cfd, (struct sockaddr*)&seraddr, sizeof(seraddr)); if(ret == -1) { perror("connect"); exit(0); }

int num = 0; // 5. 通信 while(1) { // 发送数据

char buf[128]; sprintf(buf, "hello, %dn", num++); send(cfd, buf, strlen(buf)+1, 0); printf("client say: %sn", buf); 5354555657585966676869 // 接收数据 int nums = recv(cfd, buf, sizeof(buf), 0); if(nums == -1) { perror("recv"); exit(0); } else if(nums == 0) { printf(""); break; } sleep(1); } close(cfd); return 0;}

发布者:admin,转转请注明出处:http://www.yc00.com/web/1689407381a243084.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信