电子说
UDP没有传递保证机制,如果传输中数据丢失,协议不会有任何的检测或提示。
这样的好处是传输的数据是持续的,此外它是无连接的传输,比如实时视频时,如果采用TCP,中途有一点点数据出错都会卡住,进行等待,产生延时。加入使用UDP,尽管有少量的丢帧,但数据是实时的。
从流程图可以看出,UDP比TCP的步骤少多了。
a. 创建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 }
协议族改成SOCK_DGRAM。
b. 设置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设置还是一样的。
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. 接收数据
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
函数格式 :
int recvfrom(int sockfd, char FAR *buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen);
函数功能 :
从套接字上接收一个数据报并保存源地址;
sockfd:标识一个已连接套接字的描述符
buf:接收数据缓冲区
len:接收数据缓冲区长度
flags:调用操作方式,由以下零个或多个组成
flags 说明 recv send MSG_DONTROUTE 绕过路由表查找 • MSG_DONTWAIT 仅本操作非阻塞 • • MSG_OOB 发送或接收带外数据 • • MSG_PEEK 窥看外来消息 • MSG_WAITALL 等待所有数据 • from:(可选)指针,指向装有源地址的缓冲区
fromlen:(可选)指针,指向from缓冲区长度值
返回值 :
若成功,返回读入的字节数,否则返回0;
e. 关闭
1 close(sock_fd);
2 exit(0);
a. 创建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 }
协议族改成SOCK_DGRAM。
b. 设置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. 发送数据
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
函数格式 :
int sendto(int sockfd, char FAR *buf, int len, int flags, struct sockaddr FAR *to, int FAR *tolen);
函数功能 :
向一指定目的地发送数据;
sockfd:一个标识套接字的描述字
buf:发送数据缓冲区
len:发送数据缓冲区长度
flags:调用方式标志位
to:(可选)指针,指向目的的套接字的地址
tolen:目的套接字地址的长度
返回值 :
若成功,返回发送的字节数,如果连接已中止,返回0,如果发生错误,返回-1;
d. 关闭
1 close(sock_fd);
2 exit(0);
UDP传输的客户端少了connect(),原本该在connect()函数里传入服务器地址相关信息,现在变成了在sendto()里传入。
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}
和前面TCP测试方式一样,先在Ubuntu主机上交叉编译服务器端代码,再在Ubuntu主机上编译客户端代码。
在开发板上运行服务器端代码,在Ubuntu主机先启动tmux分屏,再分别运行客户端代码。
服务器端
客户机端
全部0条评论
快来发表一下你的评论吧 !