UDP特性
UDP(User Datagram Protocol,用户数据报协议) ,是TCP/IP协议族中用于传输层 的协议,特点是无连接、不可靠、乱序(数据乱序了不会重排),不能确保数据不丢失,但数据传输效率高,延迟极低。
UDP服务器端代码实现
cpp
//服务器端代码实现
#include <stdio.h> // printf
#include <iostream> // std::cout
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h> //定义socket相关的函数和数据结构
#include <sys/types.h> //系统基础数据类型定义头文件(定义Unix/Linux 系统中用于描述「对象类型」的基本数据类型)
#include <string.h> //调strcat bzero strlen函数
#include <unistd.h> //调close函数
#define SERVER_PORT 8888 //服务器端口号
#define SERVER_IP "192.168.23.128" //服务器IP地址
int main(){
//1.创建用于通信的套接字文件描述符
int sfd = socket(AF_INET, SOCK_DGRAM, 0); //SOCK_DGRAM表示基于UDP通信方式
//参数1:AF_INET表示使用IPv4协议族
//参数2:SOCK_STREAM表示使用面向连接的TCP协议
//参数3:协议类型,通常设置为0,表示使用默认协议(参数2指定了协议时参数3填写0即可)
//返回值:成功返回sfd(socket文件描述符),失败返回-1
if(sfd == -1){
perror("socket error");
return -1;
}
printf("socket success sfd = %d\n", sfd);
//2.绑定IP地址和端口号
//2.1填充要绑定的ip地址和端口号结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SERVER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SERVER_IP); //IP地址(使用inet_addr将点分十进制字符串转换为网络字节序)
//2.2绑定工作
//参数1:要被绑定的套接字文件描述符
//参数2:要绑定的地址信息结构体,需要进行强制类型转换,防止警告
//参数3:参数2的大小
//返回值:成功返回0,失败返回-1并置位错误码
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1){
perror("bind error");
return -1;
}
printf("bind success\n");
//3.数据收发
char rbuf[128] = "";
//定义容器接收对端的地址信息结构体
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin); //socklen_t表示套接字地址结构体的长度
while(1){
//清空容器
bzero(rbuf, sizeof(rbuf));
//从客户端中读取信息
//参数1:套接字文件描述符
//参数2:存放数据的容器起始地址
//参数3:读取的数据大小
//参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
//参数5:接收对端地址信息结构体的容器
//参数6:参数5的大小
//返回值:成功返回读取字节的个数,失败返回-1并置位错误码
if(recvfrom(sfd, rbuf, sizeof(rbuf), 0, (struct sockaddr*)&cin, &socklen) == -1){
perror("recvfrom error");
return -1;
}
printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf); //客户端IP地址 客户端端口号 信息
strcat(rbuf, "*_*"); //在消息后加个笑脸
//将数据发送给客户端
//参数1:套接字文件描述符
//参数2:要发送的数据的起始地址
//参数3:要发送的数据大小
//参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
//参数5:要发送的对端 地址信息结构体
//参数6:参数5的大小
//返回值:成功返回发送的字节的个数,失败返回-1并置位错误码
sendto(sfd, rbuf, strlen(rbuf), 0, (struct sockaddr*)&cin, sizeof(cin));
printf("发送成功\n");
}
//4.关闭套接字
close(sfd);
return 0;
}
UDP客户端代码实现
cpp
//客户端代码实现
#include <stdio.h> // printf
#include <iostream> // std::cout
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h> //定义socket相关的函数和数据结构
#include <sys/types.h> //系统基础数据类型定义头文件(定义Unix/Linux 系统中用于描述「对象类型」的基本数据类型)
#include <string.h> //调strcat bzero strlen函数
#include <unistd.h> //调close函数
#define SERVER_PORT 8888 //服务器端口号
#define SERVER_IP "192.168.23.128" //服务器端IP地址
#define CLIENT_PORT 9999 //客户端口号
#define CLIENT_IP "192.168.23.128" //客户端IP地址
int main(){
//1.创建用于通信的客户端套接字文件描述符
int cfd = socket(AF_INET, SOCK_DGRAM, 0); //客户套接字文件描述符
if(cfd == -1){
perror("socket error");
return -1;
}
printf("socket success cfd = %d\n",cfd);
//2.绑定IP地址和端口号(可选)
//2.1填充要绑定的ip地址和端口号结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //通信域
cin.sin_port = htons(CLIENT_PORT); //端口号(使用htons将2字节整数转换为网络字节序)
cin.sin_addr.s_addr = inet_addr(CLIENT_IP); //IP地址(使用inet_addr将点分十进制字符串转换为网络字节序)
//2.2绑定工作
if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1){
perror("bind error");
return -1;
}
printf("bind success\n");
//3.数据收发
char wbuf[128] = "";
//填充服务器的地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SERVER_PORT);
sin.sin_addr.s_addr = inet_addr(SERVER_IP);
while(1){
//清空容器
bzero(wbuf, sizeof(wbuf));
//从终端读取用户的数据输入
fgets(wbuf, sizeof(wbuf), stdin);
wbuf[strlen(wbuf) - 1] = 0; //去除fgets读取到的多余换行符\n
//将数据发送给服务器
//参数1:套接字文件描述符
//参数2:要发送的数据的起始地址
//参数3:要发送的数据大小
//参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
//参数5:要发送的对端 地址信息结构体
//参数6:参数5的大小
//返回值:成功返回发送的字节的个数,失败返回-1并置位错误码
sendto(cfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&sin, sizeof(sin));
//接收服务器发来的数据(服务器端的地址可以不接收,置为NULL即可)
//参数1:套接字文件描述符
//参数2:存放数据的容器起始地址
//参数3:读取的数据大小
//参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
//参数5:接收对端地址信息结构体的容器
//参数6:参数5的大小
//返回值:成功返回读取字节的个数,失败返回-1并置位错误码
recvfrom(cfd, wbuf, sizeof(wbuf), 0, NULL, NULL);
printf("服务器发送的消息为:%s\n", wbuf);
}
//4.关闭套接字
close(cfd);
return 0;
}