4.UDP
UDP沒有傳遞保證機(jī)制,如果傳輸中數(shù)據(jù)丟失,協(xié)議不會(huì)有任何的檢測(cè)或提示。
這樣的好處是傳輸?shù)臄?shù)據(jù)是持續(xù)的,此外它是無(wú)連接的傳輸,比如實(shí)時(shí)視頻時(shí),如果采用TCP,中途有一點(diǎn)點(diǎn)數(shù)據(jù)出錯(cuò)都會(huì)卡住,進(jìn)行等待,產(chǎn)生延時(shí)。加入使用UDP,盡管有少量的丟幀,但數(shù)據(jù)是實(shí)時(shí)的。
4.1 UDP流程圖
4.2 UDP步驟分析
從流程圖可以看出,UDP比TCP的步驟少多了。
- 服務(wù)器端:
a. 創(chuàng)建socket
1 sock_fd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET:IPV4;SOCK_DGRAM:UDP
2 if (-1 == sock_fd)
3 {
4 fprintf(stderr,"socket error:%s\\n\\a", strerror(errno));
5 exit(1);
6 }
協(xié)議族改成SOCK_DGRAM。
b. 設(shè)置socket
1 memset(&server_addr, 0, sizeof(struct sockaddr_in));//clear
2 server_addr.sin_family = AF_INET;
3 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY:This machine all IP
4 server_addr.sin_port = htons(PORT_NUMBER);
和前面的TCP設(shè)置還是一樣的。
c. 綁定socket
1 ret = bind(sock_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr));
2 if(-1 == ret)
3 {
4 fprintf(stderr,"bind error:%s\\n\\a", strerror(errno));
5 close(sock_fd);
6 exit(1);
7 }
綁定的操作也沒有變。
d. 接收數(shù)據(jù)
1 addr_len = sizeof(struct sockaddr);
2 recv_len = recvfrom(sock_fd, recv_buf, 999, 0, (struct sockaddr *)&server_addr, &addr_len);
3 if (recv_len <= 0)
4 {
5 fprintf(stderr, "recvfrom error:%s\\n\\a", strerror(errno));
6 close(sock_fd);
7 exit(1);
8 }
9 else
10 {
11 recv_buf[recv_len] = '\\0';
12 printf("Get msg from client%d: %s\\n", client_num, recv_buf);
13 }
所需要頭文件 :
#include
#include
函數(shù)格式 :
int recvfrom(int sockfd, char FAR *buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen);
函數(shù)功能 :
從套接字上接收一個(gè)數(shù)據(jù)報(bào)并保存源地址;
sockfd:標(biāo)識(shí)一個(gè)已連接套接字的描述符
buf:接收數(shù)據(jù)緩沖區(qū)
len:接收數(shù)據(jù)緩沖區(qū)長(zhǎng)度
flags:調(diào)用操作方式,由以下零個(gè)或多個(gè)組成
flags 說明 recv send MSG_DONTROUTE 繞過路由表查找 ? MSG_DONTWAIT 僅本操作非阻塞 ? ? MSG_OOB 發(fā)送或接收帶外數(shù)據(jù) ? ? MSG_PEEK 窺看外來(lái)消息 ? MSG_WAITALL 等待所有數(shù)據(jù) ? from:(可選)指針,指向裝有源地址的緩沖區(qū)
fromlen:(可選)指針,指向from緩沖區(qū)長(zhǎng)度值
返回值 :
若成功,返回讀入的字節(jié)數(shù),否則返回0;
e. 關(guān)閉
1 close(sock_fd);
2 exit(0);
- 客戶機(jī)端:
a. 創(chuàng)建socket
1 sock_fd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET:IPV4;SOCK_DGRAM:UDP
2 if (-1 == sock_fd)
3 {
4 fprintf(stderr,"socket error:%s\\n\\a", strerror(errno));
5 exit(1);
6 }
協(xié)議族改成SOCK_DGRAM。
b. 設(shè)置socket
1 memset(&server_addr, 0, sizeof(struct sockaddr_in));//clear
2 server_addr.sin_family = AF_INET;
3 server_addr.sin_port = htons(PORT_NUMBER);
4 ret = inet_aton(argv[1], &server_addr.sin_addr);
5 if(0 == ret)
6 {
7 fprintf(stderr,"server_ip error.\\n");
8 close(sock_fd);
9 exit(1);
10 }
c. 發(fā)送數(shù)據(jù)
1 addr_len = sizeof(struct sockaddr);
2 send_len = sendto(sock_fd, send_buf, strlen(send_buf), 0, (const struct sockaddr *)&server_addr, addr_len);
3 if (send_len <= 0)
4 {
5 fprintf(stderr,"send error:%s\\n\\a", strerror(errno));
6 close(sock_fd);
7 exit(1);
8 }
所需要頭文件 :
#include
#include
函數(shù)格式 :
int sendto(int sockfd, char FAR *buf, int len, int flags, struct sockaddr FAR *to, int FAR *tolen);
函數(shù)功能 :
向一指定目的地發(fā)送數(shù)據(jù);
sockfd:一個(gè)標(biāo)識(shí)套接字的描述字
buf:發(fā)送數(shù)據(jù)緩沖區(qū)
len:發(fā)送數(shù)據(jù)緩沖區(qū)長(zhǎng)度
flags:調(diào)用方式標(biāo)志位
to:(可選)指針,指向目的的套接字的地址
tolen:目的套接字地址的長(zhǎng)度
返回值 :
若成功,返回發(fā)送的字節(jié)數(shù),如果連接已中止,返回0,如果發(fā)生錯(cuò)誤,返回-1;
d. 關(guān)閉
1 close(sock_fd);
2 exit(0);
UDP傳輸?shù)目蛻舳松倭薱onnect(),原本該在connect()函數(shù)里傳入服務(wù)器地址相關(guān)信息,現(xiàn)在變成了在sendto()里傳入。
4.3 UDP完整代碼
1/*
2* udp_server.c
3# Copyright (C) 2017 hceng,
9#include
10#include
11#include
12#include
13#include
14#include
15#include
16#include
17#include
18#include
19#include
20
21#define PORT_NUMBER 8888
22
23/* socket->bind->recvfrom/sendto->close */
24
25int main(int argc, char **argv)
26{
27 int sock_fd;
28 struct sockaddr_in server_addr;
29 struct sockaddr_in client_addr;
30 int ret;
31 int addr_len;
32 int recv_len;
33 unsigned char recv_buf[1000];
34
35 /* socket */
36 sock_fd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET:IPV4;SOCK_DGRAM:UDP
37 if (-1 == sock_fd)
38 {
39 fprintf(stderr,"socket error:%s\\n\\a", strerror(errno));
40 exit(1);
41 }
42
43 /* set sockaddr_in parameter*/
44 memset(&server_addr, 0, sizeof(struct sockaddr_in));//clear
45 server_addr.sin_family = AF_INET;
46 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY:This machine all IP
47 server_addr.sin_port = htons(PORT_NUMBER);
48
49 /* bind */
50 ret = bind(sock_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr));
51 if(-1 == ret)
52 {
53 fprintf(stderr,"bind error:%s\\n\\a", strerror(errno));
54 close(sock_fd);
55 exit(1);
56 }
57
58 while (1)
59 {
60 /* recvfrom */
61 addr_len = sizeof(struct sockaddr);
62 recv_len = recvfrom(sock_fd, recv_buf, 999, 0, (struct sockaddr *)&client_addr, &addr_len);
63 if (recv_len <= 0)
64 {
65 fprintf(stderr, "recvfrom error:%s\\n\\a", strerror(errno));
66 close(sock_fd);
67 exit(1);
68 }
69 else
70 {
71 recv_buf[recv_len] = '\\0';
72 printf("Get msg from client:%s: %s\\n", inet_ntoa(client_addr.sin_addr), recv_buf);
73 }
74 }
75
76 /* close */
77 close(sock_fd);
78 exit(0);
79}
1/*
2* udp_client.c
3# Copyright (C) 2017 hceng,
9#include
10#include
11#include
12#include
13#include
14#include
15#include
16#include
17#include
18#include
19
20#define PORT_NUMBER 8888
21
22/* socket->bind->recvfrom/sendto->close */
23int main(int argc, char *argv[])
24{
25 int sock_fd;
26 struct sockaddr_in server_addr;
27 int ret;
28 unsigned char send_buf[1000];
29 int send_len;
30 int addr_len;
31
32 if(argc != 2)
33 {
34 fprintf(stderr, "Usage:%s hostname\\n\\a", argv[0]);
35 exit(1);
36 }
37
38 /* socket */
39 sock_fd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET:IPV4;SOCK_DGRAM:UDP
40 if (-1 == sock_fd)
41 {
42 fprintf(stderr,"socket error:%s\\n\\a", strerror(errno));
43 exit(1);
44 }
45
46 /* set sockaddr_in parameter*/
47 memset(&server_addr, 0, sizeof(struct sockaddr_in));//clear
48 server_addr.sin_family = AF_INET;
49 server_addr.sin_port = htons(PORT_NUMBER);
50 ret = inet_aton(argv[1], &server_addr.sin_addr);
51 if(0 == ret)
52 {
53 fprintf(stderr,"server_ip error.\\n");
54 close(sock_fd);
55 exit(1);
56 }
57
58 while (1)
59 {
60 if (fgets(send_buf, 999, stdin))
61 {
62 /* sendto */
63 addr_len = sizeof(struct sockaddr);
64 send_len = sendto(sock_fd, send_buf, strlen(send_buf), 0, \\
65(const struct sockaddr *)&server_addr, addr_len);
66 if (send_len <= 0)
67 {
68 fprintf(stderr,"send error:%s\\n\\a", strerror(errno));
69 close(sock_fd);
70 exit(1);
71 }
72 }
73 }
74
75 /* close */
76 close(sock_fd);
77 exit(0);
78}
4.4 測(cè)試結(jié)果
和前面TCP測(cè)試方式一樣,先在Ubuntu主機(jī)上交叉編譯服務(wù)器端代碼,再在Ubuntu主機(jī)上編譯客戶端代碼。
在開發(fā)板上運(yùn)行服務(wù)器端代碼,在Ubuntu主機(jī)先啟動(dòng)tmux分屏,再分別運(yùn)行客戶端代碼。
-
服務(wù)器端
-
客戶機(jī)端
-
TCP
+關(guān)注
關(guān)注
8文章
1353瀏覽量
79055 -
UDP
+關(guān)注
關(guān)注
0文章
325瀏覽量
33931 -
網(wǎng)絡(luò)通信
+關(guān)注
關(guān)注
4文章
797瀏覽量
29795 -
網(wǎng)絡(luò)編程
+關(guān)注
關(guān)注
0文章
71瀏覽量
10074
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論