UDP 是无连接不可靠的数据包协议,不同于 TCP 提供的面向连接的可靠字节流。在介绍UDP编程模型前,先介绍UDP协议中两个重要的函数:sendto 和 recvfrom。
#include <sys/socket.h> ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags, const struct sockaddr *to, socklen_t addrlen); ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen); //两者均返回:读写字节数——成功,-1——出错前面三个参数:sockfd、buff 和 nbytes 等同于 read 和 write 函数的三个参数:套接口描述字、指向读入或写出缓冲区的指针和读写字节数。
sendto :其中 to 参数指向一个含有数据包接收者的协议地址(含 IP 地址和端口号)的套接口地址结构,其大小由 addrlen 参数指定。
recvfrom:from 参数指向一个将由该函数在返回时填写数据包发送者的协议地址(含数据发送端的 IP地址和端口号)的套接口地址结构,而在该套接口地址结构中填写的字节数则放在 addrlen 参数所指的整数中返回给调用者。简单地说就是 from 参数指向的结构体在 recvfrom 函数返回时将被对端(即:数据发送端)地址(含 IP 地址和端口号)所填充,后面的 addrlen 是个整型指针,调用前应填入 from 指向的结构体的大小,调用后将被填入对端地址的实际大小。
上面的 recvfrom 函数最后两个参数类似于 accept 的最后两个参数:函数返回时其中套接口地址结构的内容告诉我们是谁发送了数据包(UDP,通常用于UDP情况下)。
我们看看 UDP 编程模型:
相比TCP,对于服务器而言,UDP
对于客户端而言
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <string.h> #define PORT 8888 #define MAX_SIZE 1024 void udp_respon(int sockfd) { struct sockaddr_in cliaddr; int n,i; unsigned int addrlen; char msg[MAX_SIZE]; while(1) { n = recvfrom(sockfd, msg, MAX_SIZE, 0, (struct sockaddr *)&cliaddr, &addrlen); msg[n] = '\0'; fprintf(stdout, "I have recevied %s", msg); n = strlen(msg); for(i = 0; i < n; ++i) { msg[i] = msg[i] + 'A' - 'a'; } sendto(sockfd, msg, n, 0, (struct sockaddr *)&cliaddr, addrlen); } } int main(void) { int sockfd; struct sockaddr_in seraddr; sockfd = socket(AF_INET, SOCK_DGRAM,0); bzero(&seraddr, sizeof(seraddr)); //服务器端套接口结构体初始化 seraddr.sin_family = AF_INET; seraddr.sin_addr.s_addr = htonl(INADDR_ANY); seraddr.sin_port = htons(PORT); //绑定 bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr)); udp_respon(sockfd); return 0; }客户端:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <string.h> #define PORT 8888 #define MAX_SIZE 1024 void udp_request(int sockfd, const struct sockaddr_in *addr, int len) { char buffer[MAX_SIZE]; int n; while(1) { fgets(buffer, MAX_SIZE, stdin); //向目标端发送数据 sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)addr, len); printf("I have sent to server %s", buffer); printf("Waiting respond from server\n"); bzero(buffer, MAX_SIZE); //这里不需要了解数据发送端的信息,所以设置NULL n = recvfrom(sockfd, buffer, MAX_SIZE, 0, NULL, NULL); buffer[n] = 0; printf("I have received from server "); fputs(buffer, stdout); printf("\n"); } } int main() { int sockfd; struct sockaddr_in seraddr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); //目标端套接口结构体设置 bzero(&seraddr, sizeof(struct sockaddr_in)); seraddr.sin_family = AF_INET; seraddr.sin_addr.s_addr = htonl(INADDR_ANY); seraddr.sin_port = htons(PORT); udp_request(sockfd, &seraddr, sizeof(struct sockaddr_in)); close(sockfd); return 0; }对于服务器程序而言,编程步骤: