11_udp
更改。案例1:判断当前系统是大端还是小端只需要判断低地址 存放的是高字节 还是低字节。知识点1【网络字节序和主
机字节序】1、如果计算机没有考虑字节序的问题,导致传输的数据错误2、解决上述问题网络中的数据 必须是大端。发送
数据:需要将 主机字节序 转 网络字节序 hton接收数据:需要将 网络字节序 转 主机字节序 ntoh知识点
2【字节序的转换函数】1 #include <arpa/inet。h>1、主机字节序 转 网络字节序(发送数据
)1 uint32_t htonl(uint32_t hostint32);//转IP2 uint16_t h
tons(uint16_t hostint16);//转端口号2、网络字节序 转 主机字节序(接收数据)1 u
int32_t ntohl(uint32_t netint32);//转IP2 uint16_t ntohs(
uint16_t netint16);//转端口案例1:使用以htons htonl知识点3【地址转换函数】"
10。9。11。3" 点分十进制数串 (用户识别的IP地址)但是:计算机 是用32位无符号数据 存储IP地址1
、发送数据 将点分十进制数据 转换成 32为无符号数据1 #include <arpa/inet。h>1 in
t inet_pton(int family,const char *strptr, void *addrpt
r);2 功能:3 将点分十进制数串转换成32位无符号整数4 参数:5 family 协议族 AF_INET‐
‐>IPv4 AF_INET6‐‐>IPv66 strptr 点分十进制数串7 addrptr 32位无符号整
数的地址8 返回值:9 成功返回1 、 失败返回其它案例1:将"10。9。11。3"转换成32位无符号数据2、
接收数据 将32为无符号数据 转换成 点分十进制数串1 const char *inet_ntop(int f
amily, const void *addrptr,2 char *strptr, size_t len)3
功能:4 将32位无符号整数转换成点分十进制数串5 参数:6 family 协议族 AF_INET7 add
rptr 32位无符号整数8 strptr 点分十进制数串9 len strptr缓存区长度10 len的宏定
义11 #define INET_ADDRSTRLEN 16 //for ipv412 #define INE
T6_ADDRSTRLEN 46 //for ipv613 返回值:14 成功:则返回字符串的首地址15 失败
:返回NULL案例1:将32为无符号数据 转换成 点分十进制数串知识点4【UDP编程概述】1、socket网络
通信的3要素:IP、PORT、协议socket 他是网络编程接口的统称。socket 他是通信的一个端点(IP
、PORT信息),是特殊的文件描述符(套接字)。2、udp的编程流程3、socket函数创建一个套接字(通信的
端点)1 #include <sys/socket。h>2 int socket(int family,int
type,int protocol);3 功能:4 创建一个用于网络通信的socket套接字(描述符)5 参
数:6 family:协议族(AF_INET、AF_INET6、PF_PACKET等)7 type:套接字类(
SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等)8 protocol:协议类别(0、IPPR
OTO_TCP、IPPROTO_UDP等910 返回值:11 套接字12 特点:13 创建套接字时,系统不会分
配端口4、IPv4地址结构体定义 地址结构体变量1 #include <netinet/in。h>1 stru
ct in_addr2 {3 in_addr_t s_addr;//4字节4 };5 struct socka
ddr_in //IPv4地址结构体6 {7 sa_family_t sin_family;//2字节 AF_
INET AF_INET68 in_port_t sin_port;//2字节9 struct in_addr
sin_addr;//4字节10 char sin_zero[8]//8字节11 };5、通用套接字地址结构
对传递给函数的实参进行类型转换 不做赋值操作1 struct sockaddr2 {3 sa_family_t
sa_family; // 2字节4 char sa_data[14] //14字节5 };6、sendto
发送udp消息1 ssize_t sendto(int sockfd,const void *buf,size
_t nbytes,int flags,2 const struct sockaddr *to, sockle
n_t addrlen);3 功能:4 向to结构体指针中指定的ip,发送UDP数据5 参数:6 sockfd
:套接字7 buf: 发送数据缓冲区8 nbytes: 发送数据缓冲区的大小910 flags:一般为011
to: 指向目的主机地址结构体的指针12 addrlen:to所指向内容的长度13 注意:14 通过to和ad
drlen确定目的地址15 可以发送0长度的UDP数据包16 返回值:17 成功:发送数据的字符数18 失败:
‐1案例1:发送消息1 #include <stdio。h>2 #include <sys/socket。h
> //socket3 #include <unistd。h> //close4 #include <stri
ng。h> //memset strlen5 #include <netinet/in。h> //struct
sockaddr_in6 #include <arpa/inet。h> //inet_pton7 int m
ain(int argc, char const *argv[])8 {9 //创建用于通信的udp套接字10
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);11 if (soc
kfd < 0)12 {13 perror("socket");14 return 0;15 }16 prin
tf("sockfd = %d\n", sockfd);1718 //发送数据 sendto19 char b
uf[] = "hello sockfd";20 //目的地址信息21 struct sockaddr_in
dst_addr;22 memset(&dst_addr, 0, sizeof(dst_addr));23 d
st_addr。sin_family = AF_INET; //IPv424 dst_addr。sin_por
t = htons(8000); //端口25 //将目的IP 赋值到地址结构体中26 inet_pton(A
F_INET, "10。9。11。251", &dst_addr。sin_addr。s_addr);2728
//如果套接字 没有事先bind绑定固定的IP以及端口29 //那么第一次调用sendto的时候系统会给本地主
机IP,以及随机端口,作为源地址信息30 sendto(sockfd, buf, strlen(buf), 0
, (struct sockaddr *)&dst_addr, sizeof(dst_addr));3132
char buf1[] = "hello buf1";33 sendto(sockfd, buf1, strl
en(buf1), 0, (struct sockaddr *)&dst_addr, sizeof(dst_a
ddr));3435 close(sockfd);3637 return 0;38 }7、bind给套接字绑定
固定的IP和端口bind只能绑定本地机的IP地址1 创建套接字2 bind固定IP以及端口3 sendto发送
数据或recvfrom接收数据1 int bind(int sockfd,const struct socka
ddr *myaddr,socklen_t addrlen);2 功能:3 将本地协议地址与sockfd绑定4
参数:5 sockfd: socket套接字6 myaddr: 指向特定协议的地址结构指针7 addrlen
:该地址结构的长度8 返回值:9 成功:返回010 失败:其他1 #include <stdio。h>2 #i
nclude <sys/socket。h> //socket3 #include <unistd。h> //c
lose4 #include <string。h> //memset strlen5 #include <ne
tinet/in。h> //struct sockaddr_in6 #include <arpa/inet。h
> //inet_pton7 int main(int argc, char const *argv[])8
{9 //创建用于通信的udp套接字10 int sockfd = socket(AF_INET, SOCK_
DGRAM, 0);11 if (sockfd < 0)12 {13 perror("socket");14
return 0;15 }16 printf("sockfd = %d\n", sockfd);1718 //
bind固定的IP以及端口19 struct sockaddr_in my_addr;20 memset(&m
y_addr, 0, sizeof(my_addr));21 my_addr。sin_family = AF_
INET;22 my_addr。sin_port = htons(9000); //源端口23 my_addr
。sin_addr。s_addr = htonl(INADDR_ANY); //通配地址24 int ret
= bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_a
ddr));25 if (ret < 0)26 {27 perror("bind");28 return 0;
29 }3031 //发送数据 sendto32 char buf[] = "hello sockfd";33
//目的地址信息34 struct sockaddr_in dst_addr;35 memset(&dst_
addr, 0, sizeof(dst_addr));36 dst_addr。sin_family = AF_
INET; //IPv437 dst_addr。sin_port = htons(8000); //目的端口3
8 //将目的IP 赋值到地址结构体中39 inet_pton(AF_INET, "10。9。11。251",
&dst_addr。sin_addr。s_addr);4041 //如果套接字 没有事先bind绑定固定的I
P以及端口42 //那么第一次调用sendto的时候系统会给本地主机IP,以及随机端口,作为源地址信息43 s
endto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&
dst_addr, sizeof(dst_addr));4445 char buf1[] = "hello b
uf1";46 sendto(sockfd, buf1, strlen(buf1), 0, (struct s
ockaddr *)&dst_addr, sizeof(dst_addr));4748 close(sockf
d);4950 return 0;51 }528、recvfrom接收数据(阻塞)如果只负责收数据 记得事先b
ind固定的端口以及IP1 ssize_t recvfrom(int sockfd, void *buf,si
ze_t nbytes,int flags,2 struct sockaddr *from,socklen_t
*addrlen);3 功能:4 接收UDP数据,并将源地址信息保存在from指向的结构中5 参数:6 so
ckfd: 套接字7 buf:接收数据缓冲区8 nbytes:接收数据缓冲区的大小9 flags: 套接字标志
(常为0)10 from: 源地址结构体指针,用来保存数据的来源11 addrlen: from所指内容的长度
12 注意:13 通过from和addrlen参数存放数据来源信息14 from和addrlen可以为NULL
, 表示不保存数据来源15 返回值:16 成功:接收到的字符数17 失败: ‐11 #include <std
io。h>2 #include <sys/socket。h> //socket3 #include <unis
td。h> //close4 #include <string。h> //memset strlen5 #in
clude <netinet/in。h> //struct sockaddr_in6 #include <ar
pa/inet。h> //inet_pton7 int main(int argc, char const *
argv[])8 {9 //创建用于通信的udp套接字10 int sockfd = socket(AF_IN
ET, SOCK_DGRAM, 0);11 if (sockfd < 0)12 {13 perror("soc
ket");14 return 0;15 }16 printf("sockfd = %d\n", sockfd
);1718 //bind固定的IP以及端口19 struct sockaddr_in my_addr;20
memset(&my_addr, 0, sizeof(my_addr));21 my_addr。sin_fam
ily = AF_INET;22 my_addr。sin_port = htons(8000); //源端口2
3 my_addr。sin_addr。s_addr = htonl(INADDR_ANY); //通配地址24
int ret = bind(sockfd, (struct sockaddr *)&my_addr, si
zeof(my_addr));25 if (ret < 0)26 {27 perror("bind");28
return 0;29 }3031 //recvfrom接收数据32 while (1)33 {34 unsi
gned char buf[1500] = "";35 struct sockaddr_in from_add
r;36 socklen_t from_len = sizeof(from_addr);3738 int le
n = recvfrom(sockfd, buf, sizeof(buf), 0,39 (struct soc
kaddr *)&from_addr, &from_len);40 if (len < 0)41 {42 pe
rror("recvfrom");43 return 0;44 }45 //获取发送者的IP46 char i
p_str[16] = "";47 inet_ntop(AF_INET, &from_addr。sin_add
r。s_addr, ip_str, 16);48 //获取发送者的端口49 unsigned short po
rt = ntohs(from_addr。sin_port);5051 printf("IP:%s PORT:
%hu 长度:%d 消息:%s\n", ip_str, port, len, buf);52 }53 clos
e(sockfd);5455 return 0;56 }知识点5【UDP_QQ聊天程序】1 #include
<stdio。h>2 #include <sys/socket。h> //socket3 #include <
unistd。h> //close4 #include <string。h> //memset strlen5
#include <netinet/in。h> //struct sockaddr_in6 #include
<arpa/inet。h> //inet_pton7 #include <pthread。h>8 #incl
ude <stdlib。h>9 void *send_fun(void *arg)10 {11 struct
sockaddr_in dst_addr;12 memset(&dst_addr, 0, sizeof(dst
_addr));13 dst_addr。sin_family = AF_INET;1415 //根据用户输入
更改目的IP和端口16 int sockfd = *(int *)arg;17 while (1)18 {19
//sayto IP port20 char buf[128] = "";21 fgets(buf, siz
eof(buf), stdin);22 buf[strlen(buf) ‐ 1] = 0;2324 if (s
trncmp(buf, "sayto", 5) == 0)25 {26 char ip_str[16] = "
";27 unsigned short port = 0;28 sscanf(buf, "sayto %s %
hu", ip_str, &port);29 dst_addr。sin_port = htons(port);
30 inet_pton(AF_INET, ip_str, &dst_addr。sin_addr。s_addr
);31 continue;32 }33 else if (strncmp(buf, "quit", 4) =
= 0)34 {35 return NULL;36 }3738 sendto(sockfd, buf, str
len(buf), 0, (struct sockaddr *)&dst_addr, sizeof(dst_a
ddr));39 }4041 return NULL;42 }4344 void *recv_fun(void
*arg)45 {46 //获得数据 打印发送者的信息47 int sockfd = *(int *)arg
;48 while (1)49 {50 unsigned char buf[1500] = "";51 str
uct sockaddr_in from_addr;52 socklen_t from_len = sizeo
f(from_addr);5354 int len = recvfrom(sockfd, buf, sizeo
f(buf), 0,55 (struct sockaddr *)&from_addr, &from_len);
56 if (len < 0)57 {58 perror("recvfrom");59 return 0;60
}61 //获取发送者的IP62 char ip_str[16] = "";63 inet_ntop(AF_
INET, &from_addr。sin_addr。s_addr, ip_str, 16);64 //获取发送
者的端口65 unsigned short port = ntohs(from_addr。sin_port);
6667 printf("IP:%s PORT:%hu 长度:%d 消息:%s\n", ip_str, por
t, len, buf);68 }69 }70 int main(int argc, char const *
argv[])71 {72 if (argc != 2)73 {74 printf("。/a。out 8000
\n");75 return 0;76 }7778 //sockfd = socket()创建一个udp套接字
79 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);80 if (s
ockfd < 0)81 {82 perror("socket");83 return 0;84 }85 pr
intf("sockfd = %d\n", sockfd);8687 //bind固定端口IP88 struc
t sockaddr_in my_addr;89 memset(&my_addr, 0, sizeof(my_
addr));90 my_addr。sin_family = AF_INET;91 my_addr。sin_p
ort = htons(atoi(argv[1])); //源端口92 my_addr。sin_addr。s_
addr = htonl(INADDR_ANY); //通配地址93 int ret = bind(sockf
d, (struct sockaddr *)&my_addr, sizeof(my_addr));94 if
(ret < 0)95 {96 perror("bind");97 return 0;98 }99100 //
创建发送线程 将sockfd传递101 pthread_t tid1, tid2;102 pthread_cr
eate(&tid1, NULL, send_fun, (void *)&sockfd);103 //创建接收
线程 将sockfd传递104 pthread_create(&tid2, NULL, recv_fun, (
void *)&sockfd);105106 //等待线程结束pthread_join107 pthread_
join(tid1, NULL);108 pthread_cancel(tid2);109 pthread_j
oin(tid2, NULL);110111 //关闭套接字112 close(sockfd);113114
return 0;115 }