一、單播
-
UDP協(xié)議的特點:
-
無連接 、不保證傳輸可靠(可能重復到達、失序、丟失、無字節(jié)流控制(數(shù)據(jù)傳輸快的會淹沒慢的))
-
UDP傳輸
-
-
UDP 服務端(接收端)的搭建流程
-
UDP客戶端(發(fā)送端)的搭建流程
- 通信流程
-
sendto 和 recvfrom
-
這兩個函數(shù)一般在使用UDP協(xié)議時使用
-
sendto
-
功能: sendto - send a message on a socket
頭文件:
#include <sys/socket.h>
函數(shù)原型:
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
參數(shù)說明:
int socket: 通信套接字
const void *message: 要發(fā)送的數(shù)據(jù)(消息)
size_t length:發(fā)送的長度
int flags:發(fā)送的方式: 默認 0
const struct sockaddr *dest_addr: 要發(fā)送的目標地址:(指定對方的ip等)
socklen_t dest_len: 大小
返回值:
成功: 返回成功的字節(jié)數(shù)
失?。?返回-1并設置errno
- recvfrom
功能: recvfrom - receive a message from a socket
頭文件:
#include <sys/socket.h>
函數(shù)原型:
ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
int flags, struct sockaddr *restrict address,
socklen_t *restrict address_len);
參數(shù)說明:
int socket: 通信套接字
void *restrict buffer: 接收保存數(shù)據(jù)(消息)
size_t length:發(fā)送的長度
int flags:發(fā)送的方式: 默認 0
struct sockaddr *restrict address:對方的ip
socklen_t *restrict address_len: 地址長度
返回值:
成功: 返回成功的字節(jié)數(shù)
失?。?返回-1并設置errno
單播就是普通版的UDP 服務器和客戶端
代碼示例
服務器端
/*===============================================
* 文件名稱:UdpServer.c
* 創(chuàng) 建 者:
* 創(chuàng)建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
/*
if( argc < 3 )
{
puts("arg err");
return -1;
}
*/
//創(chuàng)建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//準備需要發(fā)送數(shù)據(jù)的服務器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
.sin_port = htons(8888),
.sin_addr.s_addr = inet_addr("0")
};
//綁定
int ret = bind(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("bind ");
return -1 ;
}
//發(fā)送數(shù)據(jù)
char buf[BUFSIZ] = {0};
while(1)
{
memset(buf,0,BUFSIZ);
ret = recvfrom(sockfd,buf,BUFSIZ,0,NULL,NULL);
if( -1 == ret)
{
perror("recv");
return -1;
}
// sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
puts(buf);
}
close(sockfd);
return 0;
}
客戶端
/*===============================================
* 文件名稱:UdpClient.c
* 創(chuàng) 建 者:
* 創(chuàng)建日期:2023年08月25日
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//創(chuàng)建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//準備需要發(fā)送數(shù)據(jù)的服務器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
//.sin_port = htonl(atoi(argv[2])),
.sin_port = htons(8888),
//.sin_addr.s_addr = inet_addr(argv[1])
.sin_addr.s_addr = inet_addr("192.168.18.196")
};
//發(fā)送數(shù)據(jù)
char buf[BUFSIZ] = {0};
char rbuf[BUFSIZ] = {0};
while(1)
{
fgets(buf,sizeof(buf),stdin);
int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("sendto fail");
return -1;
}
//recvfrom(sockfd,rbuf,BUFSIZ,0,NULL,NULL);
//
puts(buf);
}
close(sockfd);
return 0;
}
二、廣播
定義:給同一網(wǎng)段的所有主機 發(fā)送 數(shù)據(jù)
如何實現(xiàn):需要給發(fā)送端
開啟 廣播權限,并且 發(fā)送的目標地址是 廣播地址
代碼示例
服務器端文章來源:http://www.zghlxwxcb.cn/news/detail-756167.html
/*===============================================
* 文件名稱:UdpServer.c
* 創(chuàng) 建 者:
* 創(chuàng)建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//創(chuàng)建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//準備需要發(fā)送數(shù)據(jù)的服務器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
.sin_port = htons(6666),
.sin_addr.s_addr = inet_addr("0")
};
//綁定
int ret = bind(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("bind ");
return -1 ;
}
//發(fā)送數(shù)據(jù)
char buf[BUFSIZ] = {0};
while(1)
{
memset(buf,0,BUFSIZ);
ret = recvfrom(sockfd,buf,BUFSIZ,0,NULL,NULL);
if( -1 == ret)
{
perror("recv");
return -1;
}
// sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
puts(buf);
}
close(sockfd);
return 0;
}
客戶端
/*===============================================
* 文件名稱:UdpClient.c
* 創(chuàng) 建 者:
* 創(chuàng)建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//創(chuàng)建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//準備需要發(fā)送數(shù)據(jù)的服務器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
//.sin_port = htonl(atoi(argv[2])),
.sin_port = htons(6666),
//.sin_addr.s_addr = inet_addr(argv[1])
.sin_addr.s_addr = inet_addr("192.168.18.255") //廣播地址
};
//開播廣播權限
int opt = 1 ;
// setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
//
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
//發(fā)送數(shù)據(jù)
char buf[BUFSIZ] = {0};
char rbuf[BUFSIZ] = {0};
while(1)
{
fgets(buf,sizeof(buf),stdin);
int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("sendto fail");
return -1;
}
}
close(sockfd);
return 0;
}
三、組播(多播)
- 有選擇的接收 客戶端的數(shù)據(jù)
- 是在
接收端
加入多播組
組播在發(fā)送者和每一接收者之間實現(xiàn)點對多點網(wǎng)絡連接。如果一臺發(fā)送者同時給多個接收者傳輸相同的數(shù)據(jù),也只需
復制一份相同的數(shù)據(jù)包。它提高了數(shù)據(jù)傳送效率,減少了骨干網(wǎng)絡出現(xiàn)擁塞的可能性。組播解決了單播和廣播方式
效率低的問題。當網(wǎng)絡中的某些用戶需求特定信息時,組播源(即組播信息發(fā)送者)僅發(fā)送一次信息,組播路由器借助
組播路由協(xié)議為組播數(shù)據(jù)包建立樹型路由,被傳遞的信息在盡可能遠的分叉路口才開始復制和分發(fā)。
代碼示例(服務器端)文章來源地址http://www.zghlxwxcb.cn/news/detail-756167.html
/*===============================================
* 文件名稱:UdpServer.c
* 創(chuàng) 建 者:
* 創(chuàng)建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
/*
if( argc < 3 )
{
puts("arg err");
return -1;
}
*/
//創(chuàng)建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//準備需要發(fā)送數(shù)據(jù)的服務器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
.sin_port = htons(8888),
.sin_addr.s_addr = inet_addr("0")
};
//組播
struct ip_mreqn group = {
.imr_multiaddr.s_addr = inet_addr("224.224.224.224"),//組播地址:224.0.0.1——239
.imr_address.s_addr =htonl(INADDR_ANY)//綁定本機ip
};
//設置組播權限
if( -1 == setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group)))
{
perror("setsocket");
return -1;
}
//綁定
int ret = bind(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("bind ");
return -1 ;
}
//發(fā)送數(shù)據(jù)
char buf[BUFSIZ] = {0};
while(1)
{
memset(buf,0,BUFSIZ);
ret = recvfrom(sockfd,buf,BUFSIZ,0,NULL,NULL);
if( -1 == ret)
{
perror("recv");
return -1;
}
// sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
puts(buf);
}
close(sockfd);
return 0;
}
客戶端
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */ //man socket
#include <sys/socket.h>
#include <sys/socket.h> // man 7 ip
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h> //man 3 inet_addr
#include <netinet/in.h>
#include <arpa/inet.h> //man 2 read
#include <unistd.h>
#define SIZE 1024
#define SERV_IP "0"
#define SERV_PORT 6666
//UDP 客戶端
int main(int argc,const char *argv[])
{
int connfd;
int ret;
//1. socket
connfd = socket(AF_INET, SOCK_DGRAM, 0); // udp:SOCK_DGRAM
if(-1 == connfd)
{
perror("socket");
return -1;
}
//2. 填充ip 要連接的目標 ip 和端口
struct sockaddr_in dest_addr = {
.sin_family = AF_INET,
.sin_port = htons(SERV_PORT),
.sin_addr.s_addr = inet_addr("127.0.0.1")
};
//4.通信
char buf[SIZE] = {0};
while(1)
{
fgets(buf, sizeof(buf)-1, stdin);
if(0 == strncmp(buf, "quit",4))
{
break;
}
sendto(connfd, buf, sizeof(buf), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
}
//關閉套接字
close(connfd);
return 0;
}
到了這里,關于網(wǎng)絡編程(三)—— UDP(單播、廣播、組播)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!