一、 UDP服务器-客户端通信
UDP(User Datagram Protocol)是一种面向无连接的传输层协议,它提供了一种简单的、不可靠的数据传输服务。与TCP(Transmission Control Protocol)不同,UDP不建立连接,也不保证数据的可靠性和顺序传输。UDP被广泛用于那些对数据传输延迟要求较高,且能够容忍一定数据丢失的应用场景,如实时音视频传输、在线游戏等。
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
- 参数:
- sockfd : 通信的fd
- buf : 要发送的数据
- len : 发送数据的长度
- flags : 0
- dest_addr : 通信的另外一端的地址信息
- addrlen : 地址的内存大小
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
- 参数:
- sockfd : 通信的fd
- buf : 接收数据的数组
- len : 数组的大小
- flags : 0
- src_addr : 用来保存另外一端的地址信息,不需要可以指定为NULL
- addrlen : 地址的内存大小
二、UDP通信时,服务器为什么不使用多进程或多线程处理?
UDP是一种面向无连接的协议,与TCP不同,它在传输层不维护连接状态。因此,UDP服务器在接收到UDP数据包时,并不需要为每个客户端创建新的进程或线程来处理连接。这是因为UDP通信是无连接的,每个数据包都是独立的,服务器可以直接处理接收到的数据包,而无需维护连接状态。
对比一下:
-
TCP(传输控制协议): TCP是面向连接的协议,它在通信双方之间建立连接,保持连接状态,并提供可靠的、有序的数据传输。在TCP通信中,服务器通常需要为每个客户端连接创建新的进程或线程,以处理多个客户端同时发起的连接请求,并在连接期间保持状态。
-
UDP(用户数据报协议): UDP是无连接的协议,每个UDP数据包都是独立的,没有连接状态的维护。服务器在接收UDP数据包时,不需要为每个客户端连接创建额外的进程或线程,因为它不必保持连接状态。每个数据包都包含足够的信息,服务器可以直接处理它们,而不必关心连接的保持。
总的来说,UDP适用于那些对实时性要求高、能够容忍一定数据丢失的场景,因为它的无连接性和较低的开销使其更适合快速而简单的通信。在这样的场景下,服务器可以轻松地处理多个客户端的独立请求,而无需为每个连接创建额外的进程或线程。
三、服务器客户端代码
服务器:
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(){
// 创建一个通信的socket
int fd =socket(PF_INET,SOCK_DGRAM,0);
if(fd ==-1){
perror("socket");
exit(-1);
}
struct sockaddr_in addr;
addr.sin_family =AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY;
// 绑定
int ret = bind(fd,(struct sockaddr *)&addr,sizeof(addr));
if(ret==-1){
perror("bind");
exit(-1);
}
while (1){
char recvbuf[128];
char ipbuf[16];
struct sockaddr_in cliaddr;
int len =sizeof(cliaddr);
// 接受数据
int num =recvfrom(fd,recvbuf,sizeof(recvbuf),0,(struct sockaddr *)&cliaddr,&len);
if(num==-1){
perror("recvfrom");
exit(-1);
}
printf("client IP is : %s , Port is %d", inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ipbuf,sizeof (ipbuf)),
ntohs(cliaddr.sin_port));
printf("client say %s\n",recvbuf );
// 发生数据
sendto(fd,recvbuf, strlen(recvbuf)+1,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
}
close(fd);
return 0;
}
客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(){
// 创建一个通信的socket
int fd =socket(PF_INET,SOCK_DGRAM,0);
if(fd ==-1){
perror("socket");
exit(-1);
}
struct sockaddr_in saddr;
saddr.sin_family =AF_INET;
saddr.sin_port = htons(9999);
inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr.s_addr);
// // 绑定
// int ret = bind(fd,(struct sockaddr *)&addr,sizeof(addr));
// if(ret==-1){
// perror("bind");
// exit(-1);
// }
while (1){
char sendbuf[128];
int i=0;
sprintf(sendbuf,"hello, i am a client %d\n",i++);
sendto(fd,sendbuf, strlen(sendbuf)+1,0,(struct sockaddr *)&saddr,sizeof(saddr));
// char ipbuf[16];
// struct sockaddr_in cliaddr;
// int len =sizeof(cliaddr);
// 接受数据
int num =recvfrom(fd,sendbuf,sizeof(sendbuf),0,NULL,NULL);
if(num==-1){
perror("recvfrom");
exit(-1);
}
printf("SERVER say %s\n",sendbuf);
// 发生数据
sleep(1);
}
close(fd);
return 0;
}