由于UDP是无连接、尽力传输的,所以Server端绑定完IP、端口号后,使用recvfrom可以阻塞等待客户端的数据,而且Client端通过sendto发送的数据包直接发送到互联网(也是基于IP、端口号)这种操作是不担保Server端是否收到的,适用于实时音视频传输、DNS的域名解析
一、Sendto
实际上,sendto和recvfrom都是对于send和recv的扩展-----增加参数(用于绑定IP、端口号)
因为UDP是无连接的,想要传输信息实际上还是需要对象的信息,只不过它的信息不用像TCP编程中实际地对sock_fd进行绑定,而是直接通过参数绑定
#include <sys/types.h>
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flagsstruct sockaddr *dest_addr, socklen_t addrlen)params: 前三个参数同writeflags 一般填0---此时同writeMSG_DONTWAIT 非阻塞版本MSG_OOB 用于发送TCP类型的带外数据(out-of-band)dest_addr 目标的结构体指针(配置IP、端口号)addrlen 目标的结构体大小
二、Recvfrom
#include <sys/types.h>
#include <sys/socket.h>ssize_t recvfrom(int sockfd, const void *buf, size_t len, int flagsstruct sockaddr *src_addr, socklen_t *addrlen)params: 前三个参数同readflags 一般填0---此时同readMSG_DONTWAIT 非阻塞版本MSG_OOB 用于发送TCP类型的带外数据(out-of-band)src_addr 发送方的结构体指针(配置IP、端口号)addrlen 发送方的结构体大小的指针----注意和sendto中的区别!!return: 成功返回收到字节数,失败返回-1
三、服务器端
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h> //exit
#include <string.h> //bzero
#include <strings.h> //strncasecmp 忽略大小写比较
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define SERV_PORT (5001)
#define SERV_IP "127.0.0.1"
#define BUFSIZE (128)
#define QUIT_STR "quit"int main(void)
{int sock_fd;struct sockaddr_in sin,cin;//1.创建 注意套接字类型变化---数据报套接字sock_fd = socket(AF_INET,SOCK_DGRAM,0);if( sock_fd == -1){perror("socket");exit(1);}//优化:允许绑定地址快速重用int b_reuse = 1;setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));//2.绑定 bzero(&sin,sizeof(sin));sin.sin_family = AF_INET;sin.sin_port = htons(SERV_PORT);sin.sin_addr.s_addr = htonl(INADDR_ANY);if( (bind(sock_fd,(struct sockaddr*)&sin,sizeof(sin))) < 0 ){perror("bind");exit(1);}//3.循环服务器模型char rd_buf[BUFSIZ];socklen_t cin_len = sizeof(cin);while(1){bzero(rd_buf,BUFSIZ);if( recvfrom(sock_fd,rd_buf,BUFSIZ-1,(struct sockaddr*)&cin,&cin_len) < 0 ){perror("recvfrom");continue;} //发送方的信息处理char cin_ip[16];if( inet_ntop(AF_INET,(void*)&cin.sin_addr,cin_ip,sizeof(cin)) == 0){perror("inet_ntop");exit(1);}printf("Received from(%s:%d),data:%s",cin_ip,ntohs(cin.sin_port),rd_buf);}close(sock_fd);return 0;
}
四、客户端
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h> //exit
#include <string.h> //bzero
#include <strings.h> //strncasecmp 忽略大小写比较
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define SERV_PORT (5001)
#define SERV_IP "127.0.0.1"
#define BUFSIZE (128)
#define QUIT_STR "quit"void usage(char *s)
{printf("\nWarning:too few parameters!\n");printf("\n\t%s SERV_IP SERV_PORT\n",s);printf("SERV_PORT must > 5000\n");
}int main(int argc, char **argv)
{if( argc != 3){usage(argv[0]);exit(1);}int sock_fd;struct sockaddr_in sin;//1.创建sock_fd = socket(AF_INET,SOCK_DGRAM,0);if(sock_fd == -1){perror("socket");exit(1);}//配置sockaddr_in信息---用于sendtobzero(&sin,sizeof(sin));sin.sin_family = AF_INET;//端口号、IP都从输入参数获得u_short port = (u_short)atoi(argv[2]);if(port<5000){perror("port");exit(1);} sin.sin_port = htons(port);if( inet_pton(AF_INET,argv[1],(void*)&sin.sin_addr) != 1){perror("inet_pton");exit(1);}char wr_buf[BUFSIZE];while(1){//键盘获取内容-->发送到服务器bzero(wr_buf,BUFSIZE);if( fgets(wr_buf,BUFSIZE-1,stdin) == NULL ){perror("fgets");continue;}sendto(sock_fd,wr_buf,strlen(wr_buf),0,(struct sockaddr*)&sin,sizeof(sin));if( strncasecmp(wr_buf,QUIT_STR,strlen(QUIT_STR)) == 0) //输入了quit{break;}}close(sock_fd);return 0;
}