1. UDP协议介绍
UDP协议 相对TCP协议来讲属于不可靠协议,UDP协议是广播方式发送数据,没有服务器和客户端的概念。
在Linux下使用socket创建UDP的套接字时,属性要选择数据报类型SOCK_DGRAM
。
sockfd=socket(AF_INET,SOCK_DGRAM,0);
2. UDP协议发送和接收数据的函数
2.1 recvfrom函数
UDP使用recvfrom()函数接收数据,他类似于标准的read(),但是在recvfrom()函数中要指明数据的目的地址。
代码语言:javascript复制#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * from, size_t *addrlen);
返回值
成功返回接收到数据的长度,负数失败
前三个参数等同于函数read()的前三个参数,flags参数是传输控制标志。最后两个参数类似于accept的最后两个参数(接收客户端的IP地址)。
2.2 sendto函数
UDP使用sendto()函数发送数据,他类似于标准的write(),但是在sendto()函数中要指明目的地址。
代码语言:javascript复制#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr * to, int addrlen);
返回值
成功返回发送数据的长度,失败返回-1
前三个参数等同于函数read()的前三个参数,flags参数是传输控制标志。
参数to指明数据将发往的协议地址,他的大小由addrlen参数来指定。
2.3 设置套接字属性
代码语言:javascript复制#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。
参数
sockfd:标识一个套接口的描述字。
level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
optname:需设置的选项。
optval:指针,指向存放选项值的缓冲区。
optlen:optval缓冲区的长度。
UDP协议发送数据时,设置具有广播特性: 默认情况下socket不支持广播特性
代码语言:javascript复制char bBroadcast=1;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(char));
3. 案例: UDP协议数据收发
代码语言:javascript复制#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <poll.h>
#define SEND_MSG "1314520" //发送的数据包
#define PORT 8888 //固定的端口号
int sockfd;
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("./app <广播地址> 当前程序固定的端口号是8888n");
return 0;
}
/*1. 创建socket套接字*/
sockfd=socket(AF_INET,SOCK_DGRAM,0);
//设置端口号的复用功能
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
/*2. 绑定端口号与IP地址*/
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(PORT); // 端口号0~65535
addr.sin_addr.s_addr=INADDR_ANY; //inet_addr("0.0.0.0"); //IP地址
if(bind(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr))!=0)
{
printf("UDP服务器:端口号绑定失败.n");
return 0;
}
/*3. 接收数据*/
unsigned char buff[1024 1];
int cnt;
struct sockaddr_in client_addr;
socklen_t addrlen=sizeof(struct sockaddr_in);
struct pollfd fds;
fds.fd=sockfd;
fds.events=POLLIN;
while(1)
{
cnt=poll(&fds,1,1000);
if(cnt>0)
{
cnt=recvfrom(sockfd,buff,1024,0,(struct sockaddr *)&client_addr,&addrlen);
buff[cnt]='