UDP网络编程

字节序与UDP网络编程:

一、编程准备-字节序、地址转换

1.1 字节序概述
字节序指多字节数据的存储顺序
小端格式:将低位字节数据存储在低地址
大端格式:将高位字节数据存储在低地址
如何判断当前系统的字节序:

1 #include <stdio.h>
2
3 //判断当前系统的字节序
4
5 union un
6 {
7 int a;
8 char b;
9 };
10
11 int main(int argc, char const *argv[])
12 {
13 union un myun;
14 myun.a = 0x12345678;
15
16 printf("a = %#x\n", myun.a);
17 printf("b = %#x\n", myun.b);
18
19 if(myun.b == 0x78)
20 {
21 printf("小端存储\n");
22 }
23 else
24 {
25 printf("大端存储\n");
26 }
27
28 return 0;
29 }

1.2 字节序转换函数
1、网络协议指定了通讯字节序—大端
2、只有在多字节数据处理时才需要考虑字节序
3、运行在同一台计算机上的进程相互通信时,一般不用考虑字节序
4、异构计算机之间通讯,需要转换自己的字节序为网络字节序
在需要字节序转换的时候一般调用特定字节序转换函数

1 host ‐‐> network
2 1 ‐‐ htonl
3 #include <arpa/inet.h>
4 uint32_t htonl(uint32_t hostint32);
5 功能:
632位主机字节序数据转换成网络字节序数据
7 参数:
8 hostint32:待转换的32位主机字节序数据
9 返回值:
10 成功:返回网络字节序的值
11
12 2 ‐‐ htons
13 #include <arpa/inet.h>
14 uint16_t htons(uint16_t hostint16);
15 功能:
1616位主机字节序数据转换成网络字节序数据
17 参数:
18 uint16_tunsigned short int
19 hostint16:待转换的16位主机字节序数据
20 返回值:
21 成功:返回网络字节序的值
22
23 network ‐‐> host
24 3 ‐‐ ntohl
25 #include <arpa/inet.h>
26 uint32_t ntohl(uint32_t netint32);
27 功能:
2832位网络字节序数据转换成主机字节序数据
29 参数:
30 uint32_tunsigned int
31 netint32:待转换的32位网络字节序数据
32 返回值:
33 成功:返回主机字节序的值
34
35 4 ‐‐ ntohs
36 #include <arpa/inet.h>
37 uint16_t ntohs(uint16_t netint16);
38 功能:
3916位网络字节序数据转换成主机字节序数据
40 参数:
41 uint16_tunsigned short int
42 netint16:待转换的16位网络字节序数据
43 返回值:
44 成功:返回主机字节序的值

1.3 地址转换函数
1.3.1 inet_pton()

1 字符串ip地址转整型数据
2 #include <arpa/inet.h>
3 int inet_pton(int family,const char *strptr, void *addrptr);
4 功能:
5 将点分十进制数串转换成32位无符号整数
6 参数:
7 family 协议族
8 AF_INET IPV4网络协议
9 AF_INET6 IPV6网络协议
10 strptr 点分十进制数串
11 addrptr 32位无符号整数的地址
12 返回值:
13 成功返回1
14 失败返回其它

1.3.2 inet_ntop()

1 整型数据转字符串格式ip地址
2 #include <arpa/inet.h>
3 const char *inet_ntop(int family, const void *addrptr,
4 char *strptr, size_t len);
5 功能:
632位无符号整数转换成点分十进制数串
7 参数:
8 family 协议族
9 addrptr 32位无符号整数
10 strptr 点分十进制数串
11 len strptr缓存区长度
12 len的宏定义
13 #define INET_ADDRSTRLEN 16 //for ipv4
14 #define INET6_ADDRSTRLEN 46 //for ipv6
15 返回值:
16 成功:则返回字符串的首地址
17 失败:返回NULL

1.3.3 inet_addr()和inet_ntoa()

这两个函数只能用在ipv4地址的转换
1 #include <sys/socket.h>
2 #include <netinet/in.h>
3 #include <arpa/inet.h>
4
5 in_addr_t inet_addr(const char *cp);
6 功能:将点分十进制ip地址转化为整形数据
7 参数:
8 cp:点分十进制的IP地址
9 返回值:
10 成功:整形数据
11
12 char *inet_ntoa(struct in_addr in);
13 功能:将整形数据转化为点分十进制的ip地址
14 参数:
15 in:保存ip地址的结构体
16 返回值:
17 成功:点分十进制的IP地址

UDP网络编程流程:

服务器:
创建套接字 socket( )
将服务器的ip地址、端口号与套接字进行绑定 bind( )
接收数据 recvfrom()
发送数据 sendto()
客户端:
创建套接字 socket()
发送数据 sendto()
接收数据 recvfrom()
关闭套接字 close()

1 //udp客户端的实现
2 #include <stdio.h> //printf
3 #include <stdlib.h> //exit
4 #include <sys/types.h>
5 #include <sys/socket.h> //socket
6 #include <netinet/in.h> //sockaddr_in
7 #include <arpa/inet.h> //htons inet_addr
8 #include <unistd.h> //close
9 #include <string.h>
10
11 int main(int argc, char const *argv[])
12 {
13 if(argc < 3)
14 {
15 fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
16 exit(1);
17 }
18
19 int sockfd; //文件描述符
20 struct sockaddr_in serveraddr; //服务器网络信息结构体
21 socklen_t addrlen = sizeof(serveraddr);
22
23 //第一步:创建套接字
24 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
25 {
26 perror("fail to socket");
27 exit(1);
28 }
29
30 //客户端自己指定自己的ip地址和端口号,一般不需要,系统会自动分配
31 #if 0
32 struct sockaddr_in clientaddr;
33 clientaddr.sin_family = AF_INET;
34 clientaddr.sin_addr.s_addr = inet_addr(argv[3]); //客户端的ip地址
35 clientaddr.sin_port = htons(atoi(argv[4])); //客户端的端口号
36 if(bind(sockfd, (struct sockaddr *)&clientaddr, addrlen) < 0)
37 {
38 perror("fail to bind");
39 exit(1);
40 }
41 #endif
42
43 //第二步:填充服务器网络信息结构体
44 //inet_addr:将点分十进制字符串ip地址转化为整形数据
45 //htons:将主机字节序转化为网络字节序
46 //atoi:将数字型字符串转化为整形数据
47 serveraddr.sin_family = AF_INET;
48 serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
49 serveraddr.sin_port = htons(atoi(argv[2]));
50
51 //第三步:进行通信
52 char buf[32] = "";
53 while(1)
54 {
55 fgets(buf, sizeof(buf), stdin);
56 buf[strlen(buf)1] = '\0';
57
58 if(sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serve
raddr, sizeof(serveraddr)) < 0)
59 {
60 perror("fail to sendto");
61 exit(1);
62 }
63
64 char text[32] = "";
65 if(recvfrom(sockfd, text, sizeof(text), 0, (struct sockaddr *)&s
erveraddr, &addrlen) < 0)
66 {
67 perror("fail to recvfrom");
68 exit(1);
69 }
70 printf("from server: %s\n", text);
71 }
72 //第四步:关闭文件描述符
73 close(sockfd);
74
75 return 0;
76 }
1 //udp服务器的实现
2 #include <stdio.h> //printf
3 #include <stdlib.h> //exit
4 #include <sys/types.h>
5 #include <sys/socket.h> //socket
6 #include <netinet/in.h> //sockaddr_in
7 #include <arpa/inet.h> //htons inet_addr
8 #include <unistd.h> //close
9 #include <string.h>
10
11 int main(int argc, char const *argv[])
12 {
13 if(argc < 3)
14 {
15 fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
16 exit(1);
17 }
18
19 int sockfd; //文件描述符
20 struct sockaddr_in serveraddr; //服务器网络信息结构体
21 socklen_t addrlen = sizeof(serveraddr);
22
23 //第一步:创建套接字
24 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
25 {
26 perror("fail to socket");
27 exit(1);
28 }
29
30 //第二步:填充服务器网络信息结构体
31 //inet_addr:将点分十进制字符串ip地址转化为整形数据
32 //htons:将主机字节序转化为网络字节序
33 //atoi:将数字型字符串转化为整形数据
34 serveraddr.sin_family = AF_INET;
35 serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
36 serveraddr.sin_port = htons(atoi(argv[2]));
37
38 //第三步:将套接字与服务器网络信息结构体绑定
39 if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
40 {
41 perror("fail to bind");
42 exit(1);
43 }
44
45 while(1)
46 {
47 //第四步:进行通信
48 char text[32] = "";
49 struct sockaddr_in clientaddr;
50 if(recvfrom(sockfd, text, sizeof(text), 0, (struct sockaddr *)&c
lientaddr, &addrlen) < 0)
51 {
52 perror("fail to recvfrom");
53 exit(1);
54 }
55 printf("
[%s ‐ %d]: %s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port),
ext);
56
57 strcat(text, " *_*");
58
59 if(sendto(sockfd, text, sizeof(text), 0, (struct sockaddr *)&cli
entaddr, addrlen) < 0)
60 {
61 perror("fail to sendto");
62 exit(1);
63 }
64 }
65
66 //第四步:关闭文件描述符
67 close(sockfd);
68
69 return 0;
70 }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值