目錄
0x01 UDP協(xié)議
一、UDP通信簡介以及接口
二、UDP的接口
三、UDP收發(fā)例程
0x02 廣播
一、設置廣播數(shù)據(jù)函數(shù)接口
二、廣播代碼實現(xiàn)
0x03 組播(多播)
一、組播地址
二、設置組播函數(shù)接口
三、代碼實現(xiàn)
0x01 UDP協(xié)議
一、UDP通信簡介以及接口
UDP是一個面向無連接的,不可靠的服務,功能即為在IP的數(shù)據(jù)報服務之上增加了最基本的服務:復用和分用以及差錯檢測。
-
UDP通信不需要建立連接,因此不需要進行connect()操作。
-
UDP通信過程中,每次都需要指定數(shù)據(jù)接收端的IP和端口。
-
UDP不對收到的數(shù)據(jù)進行排序,在UDP報文的首部中并沒有關于數(shù)據(jù)順序的信息。
-
UDP對接收到的數(shù)據(jù)報不回復確認信息,發(fā)送端不知道數(shù)據(jù)是否被正確接收,也不會重發(fā)數(shù)據(jù)。
-
如果發(fā)生了數(shù)據(jù)丟失,不存在丟一半的情況,如果丟當前這個數(shù)據(jù)報就全部丟失了。
-
UDP沒有擁塞控制,應用層能夠更好的控制要發(fā)送的數(shù)據(jù)和發(fā)送時間,網絡中的擁塞控制也不會影響主機的發(fā)送速率,能容忍一些數(shù)據(jù)的丟失,但是不能允許有較大的時延。
二、UDP的接口
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
- 參數(shù):
- sockfd : 通信的fd
- buf : 要發(fā)送的數(shù)據(jù)
- len : 發(fā)送數(shù)據(jù)的長度
- flags : 0
- dest_addr : 通信的另外一端的地址信息
- addrlen : 地址的內存大小
- 返回:
-n :發(fā)送字節(jié)的數(shù)量
-0 :失敗
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
- 參數(shù):
- sockfd : 通信的fd
- buf : 接收數(shù)據(jù)的數(shù)組
- len : 數(shù)組的大小
- flags : 0
- src_addr : 用來保存另外一端的地址信息,不需要可以指定為NULL
- addrlen : 地址的內存大小
- 返回:
- n:成功返回字節(jié)個數(shù)
- 0:失敗
三、UDP收發(fā)例程
客戶端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
// 1.創(chuàng)建一個通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
// 服務器的地址信息
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr.s_addr);
int num = 0;
// 3.通信
while(1) {
// 發(fā)送數(shù)據(jù)
char sendBuf[128];
sprintf(sendBuf, "hello , i am client %d \n", num++);
sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&saddr, sizeof(saddr));
// 接收數(shù)據(jù)
int num = recvfrom(fd, sendBuf, sizeof(sendBuf), 0, NULL, NULL);
printf("server say : %s\n", sendBuf);
sleep(1);
}
close(fd);
return 0;
}
? 服務端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
// 1.創(chuàng)建一個通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY;
// 2.綁定
int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
// 3.通信
while(1) {
char recvbuf[128];
char ipbuf[16];
struct sockaddr_in cliaddr;
int len = sizeof(cliaddr);
// 接收數(shù)據(jù)
int num = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&cliaddr, &len);
printf("client IP : %s, Port : %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
ntohs(cliaddr.sin_port));
printf("client say : %s\n", recvbuf);
// 發(fā)送數(shù)據(jù)
sendto(fd, recvbuf, strlen(recvbuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
}
close(fd);
return 0;
}
0x02 廣播
在局域網中可以使用單播的形式,即一對一通訊,也可以使用廣播的形式,即向子網中多臺計算機發(fā)送消息,并且子網中所有的計算機都可以接收到發(fā)送方發(fā)送的消息,每個廣播消息都包含一個特殊的IP地址,這個IP中子網內主機標志部分的二進制全部為1(即主機IP為255)。
例如192.168.10.20,其中20為主機IP,其他的為網絡IP。若主機IP為0,則代表這是個子網IP;若為255,則代表為廣播IP。
-
只能在局域網中使用
-
客戶端需要綁定服務器廣播使用的端口,才可以接收到廣播消息,也就是說客戶端需要綁定IP為192.168.10.255,并且需要綁定與廣播的服務器的端口。
一、設置廣播數(shù)據(jù)函數(shù)接口
// 設置廣播屬性的函數(shù)
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的大小
二、廣播代碼實現(xiàn)
服務端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
// 1.創(chuàng)建一個通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
// 2.設置廣播屬性
int op = 1;
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));
// 3.創(chuàng)建一個廣播的地址
struct sockaddr_in cliaddr;
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(9999);
inet_pton(AF_INET, "192.168.193.255", &cliaddr.sin_addr.s_addr); //本機的廣播地址使用命令ifconfig查看
// 3.通信
int num = 0;
while(1) {
char sendBuf[128];
sprintf(sendBuf, "hello, client....%d\n", num++);
// 發(fā)送數(shù)據(jù)
sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
printf("廣播的數(shù)據(jù):%s\n", sendBuf);
sleep(1);
}
close(fd);
return 0;
}
客戶端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
// 1.創(chuàng)建一個通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
struct in_addr in;
// 2.客戶端綁定本地的IP和端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY; //綁定本機IP
int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
// 3.通信
while(1) {
char buf[128];
// 接收數(shù)據(jù)
int num = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
printf("server say : %s\n", buf);
}
close(fd);
return 0;
}
0x03 組播(多播)
單播地址標識單個 IP 接口,廣播地址標識某個子網的所有 IP 接口,多播地址標識一組 IP 接口。單播和廣播是尋址方案的兩個極端(要么單個要么全部),多播則意在兩者之間提供一種折中方案。多播數(shù)據(jù)報只應該由對它感興趣的接口接收,也就是說由運行相應多播會話應用系統(tǒng)的主機上的接口接收。另外,廣播一般局限于局域網內使用,而多播則既可以用于局域網,也可以跨廣域網使用。
-
組播既可以用于局域網,也可以用于廣域網。
-
客戶端需要加入多播組,才能接收到多播的數(shù)據(jù)。
一、組播地址
IP多播通信必須依賴于IP多播地址,在IPv4中它的范圍從224.0.0.0
到239.255.255.255
,并被劃分為局部鏈接多播地址、預留多播地址和管理權限多播地址三類:
IP地址 | 說明 |
---|---|
224.0.0.0~224.0.0.255 | 局部鏈接多播地址:是為路由協(xié)議和其它用途保留的地址,路由器并不轉發(fā)屬于此范圍的IP包 |
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 | 本地管理組播地址,可供組織內部使用,類似于私有 IP 地址,不能用于 Internet,可限制多播范圍 |
二、設置組播函數(shù)接口
int setsockopt(int sockfd, int level, int optname,const void *optval,socklen_t optlen);
// 服務器設置多播的信息,外出接口
- level : IPPROTO_IP
- optname : IP_MULTICAST_IF
- optval : struct in_addr
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
// 客戶端加入到多播組:
- level : IPPROTO_IP
- optname : IP_ADD_MEMBERSHIP
- optval : struct ip_mreq
struct ip_mreq
{
/* IP multicast address of group.*/
struct in_addr imr_multiaddr; // 組播的IP地址
/* Local IP address of interface.*/
struct in_addr imr_interface; // 本地的IP地址
};
以上的參數(shù)設置主要參照于《UNIX網絡編程》。
三、代碼實現(xiàn)
服務端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
// 1.創(chuàng)建一個通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
// 2.設置多播的屬性,設置外出接口
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));
// 3.初始化客戶端的地址信息,在多播中需要表明客戶端的信息
struct sockaddr_in cliaddr;
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(9999);
inet_pton(AF_INET, "239.0.0.10", &cliaddr.sin_addr.s_addr);
// 3.通信
int num = 0;
while(1) {
char sendBuf[128];
sprintf(sendBuf, "hello, client....%d\n", num++);
// 發(fā)送數(shù)據(jù)
sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
printf("組播的數(shù)據(jù):%s\n", sendBuf);
sleep(1);
}
close(fd);
return 0;
}
客戶端代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-526384.html
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
// 1.創(chuàng)建一個通信的socket,使用UDP通信協(xié)議
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
struct in_addr in;
// 2.客戶端綁定本地的IP和端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
struct ip_mreq op;
inet_pton(AF_INET, "239.0.0.10", &op.imr_multiaddr.s_addr);
op.imr_interface.s_addr = INADDR_ANY;
// 加入到多播組
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &op, sizeof(op));
// 3.通信
while(1) {
char buf[128];
// 接收數(shù)據(jù)
int num = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
printf("server say : %s\n", buf);
}
close(fd);
return 0;
}
需要注意的是,多播與廣播只能UDP,對于TCP只能一對一。文章來源地址http://www.zghlxwxcb.cn/news/detail-526384.html
到了這里,關于Linux網絡編程(四)——UDP通信的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!