网站制作 网站,亚洲永久免费云服务器,怎样制作一个个人网站,数据库查询网站模板udp是一个面向无连接的#xff0c;不安全的#xff0c;报式传输层协议#xff0c;udp的通信过程默认也是阻塞的。使用UDP进行通信#xff0c;服务器和客户端的处理步骤比TCP要简单很多#xff0c;并且两端是对等的 #xff08;通信的处理流程几乎是一样的#xff09;不安全的报式传输层协议udp的通信过程默认也是阻塞的。使用UDP进行通信服务器和客户端的处理步骤比TCP要简单很多并且两端是对等的 通信的处理流程几乎是一样的也就是说并没有严格意义上的客户端和服务器端。 UDP通信不需要建立连接 因此不需要进行connect()操作在通信过程中每次都需要指定数据接收端的IP和端口。UDP不对收到的数据进行排序在UDP报文的首部中并没有关于数据顺序的信息。 UDP对接收到的数据报不回复确认信息发送端不知道数据是否被正确接收也不会重发数据。如果发生了数据丢失不存在丢一半的情况如果丢当前这个数据包就全部丢失了
UDP通信过程虽然默认还是阻塞的但是通信函数和TCP不同操作函数原型如下
// 接收数据, 如果没有数据,该函数阻塞
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
参数:
sockfd: 基于udp的通信的文件描述符buf: 指针指向的地址用来存储接收的数据len: buf指针指向的内存的容量, 最多能存储多少字节flags: 设置套接字属性一般使用默认属性指定为0即可src_addr: 发送数据的一端的地址信息IP和端口都存储在这里边, 是大端存储的如果这个参数中的信息对当前业务处理没有用处, 可以指定为NULL, 不保存这些信息addrlen: 类似于accept() 函数的最后一个参数, 是一个传入传出参数传入的是src_addr参数指向的内存的大小, 传出的也是这块内存的大小。如果src_addr参数指定为NULL, 这个参数也指定为NULL即可返回值成功返回接收的字节数失败返回-1
// 发送数据函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
参数:
sockfd: 基于udp的通信的文件描述符buf: 这个指针指向的内存中存储了要发送的数据len: 要发送的数据的实际长度flags: 设置套接字属性一般使用默认属性指定为0即可dest_addr: 接收数据的一端对应的地址信息, 大端的IP和端口addrlen: 参数 dest_addr 指向的内存大小返回值函数调用成功返回实际发送的字节数调用失败返回-1
服务端代码示例
在UDP通信过程中服务器和客户端都可以作为数据的发送端和数据接收端假设服务器端是被动接收数据客户端是主动发送数据那么在服务器端就必须绑定固定的端口了。
#include iostream
#include arpa/inet.h
#include unistd.h
#include cstringint main() {int fd socket(AF_INET, SOCK_DGRAM, 0);if (fd -1) {perror(socket);return -1;}// 初始化服务器地址sockaddr_in server_addr;server_addr.sin_family AF_INET;server_addr.sin_port htons(9999); server_addr.sin_addr.s_addr INADDR_ANY;if (bind(fd, (struct sockaddr*)server_addr, sizeof(server_addr)) -1) {perror(bind failed);exit(EXIT_FAILURE);
}char buffer[8888];sockaddr_in client_addr;socklen_t client_addr_len sizeof(client_addr);while (1) {// 接收客户端数据ssize_t recv_len recvfrom(fd, buffer, sizeof(buffer)-1, 0,(struct sockaddr*)client_addr,client_addr_len);if (recv_len -1) {perror(recvfrom failed);continue;}buffer[recv_len] \0; // 确保字符串终止// 打印客户端信息char client_ip[INET_ADDRSTRLEN];inet_ntop(AF_INET, client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);std::cout Client ( client_ip : ntohs(client_addr.sin_port) ): buffer std::endl;// 构造响应添加前缀char prefix[] server say:;char response[sizeof(buffer)];sprintf(response, %s%s, prefix, buffer);// 发送响应使用正确的长度ssize_t send_len sendto(fd, response, strlen(response), 0,(const struct sockaddr*)client_addr,client_addr_len);if (send_len -1) {perror(sendto failed);continue;}}close(fd);return 0;
}
作为数据接收端服务器端通过bind()函数绑定了固定的端口然后基于这个固定的端口通过recvfrom()函数接收客户端发送的数据同时通过这个函数也得到了数据发送端的地址信息recvfrom的第三个参数这样就可以通过得到的地址信息通过sendto()函数给客户端回复数据了。
客户端代码示例
#include iostream
#include arpa/inet.h
#include string
#include unistd.h
#include pthread.h int main() {int fd socket(AF_INET, SOCK_DGRAM, 0);if (fd -1) {perror(socket);return -1;}// 初始化服务器地址sockaddr_in server_addr;server_addr.sin_family AF_INET;server_addr.sin_port htons(9999); inet_pton(AF_INET, 192.168.175.130, server_addr.sin_addr); int num 0;std::string t std::to_string(pthread_self());std::string s :Hello World!!!;while (1) {std::string S t s std::to_string(num);// 发送数据到服务器ssize_t send_len sendto(fd, S.data(), S.size(), 0,(const struct sockaddr*)server_addr,sizeof(server_addr));if (send_len -1) {perror(sendto failed);continue;}// 接收服务器响应sockaddr_in server_response_addr;socklen_t addr_len sizeof(server_response_addr);char buffer[1024] {0};ssize_t recv_len recvfrom(fd, buffer, sizeof(buffer)-1, 0,(struct sockaddr*)server_response_addr,addr_len);if (recv_len -1) {perror(recvfrom failed);continue;}// 打印服务器地址和响应char str[INET_ADDRSTRLEN];std::cout Server ( inet_ntop(AF_INET, server_response_addr.sin_addr, str, INET_ADDRSTRLEN) : ntohs(server_response_addr.sin_port) ): buffer std::endl;sleep(1);}close(fd);return 0;
}
作为数据发送端客户端不需要绑定固定端口客户端使用的端口是随机绑定的也可以调用bind()函数手动进行绑定。
同时开启三个客户端一个服务端运行结果 UDP是一种无连接的传输层协议其特性天然支持多客户端同时通信服务器不需要与每个客户端建立持久连接只需接收来自不同源地址的数据包每个客户端发送的 UDP 数据包都是独立的服务器可以逐个处理每个数据包都包含发送方的 IP 和端口信息服务器可以据此区分不同客户端。
所以可以启动多个客户端与服务器进行通信UDP 协议的特性会确保每个客户端的请求被正确路由和处理。