文章目录
1,UDP循环服务器模型:
socket(...);
bind(...);
while(1){
recvfrom(...);
process(...);
sendto(...);
}
2,UDP的使用场景
- 实时的音视频传输
- DNS的域名解析
3,UDP数据发送和接受sendto()、recvfrom()
ssize_t sendto(int socket, void *message, size_t length, int flags, struct sockaddr *dest_addr, socklen_t dest_len);
ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);
这两个函数一般在使用UDP协议时使用
4,UDP循环服务器示例(可同时连接多个客户端)
4.1,头文件 net.h
#ifndef __NET_H__
#define __NET_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define SERV_IP_ADDR "192.168.31.100"
#define SERV_PORT 5005
//#define BACKLOG 5
#define QUIT_STR "quite"
#endif
4.2,客户端代码client.c
/* UDP demo */
/*./client serv_ip serv_port */
#include "net.h"
void usage(char *s)
{
printf("this is a UDP demo!
");
printf("Usage:
%s
",s);
printf(" serv_ip: UDP server ip address
");
printf(" serv_port: UDP server port(>5000)
");
}
int main(int argc, const char *argv[])
{
int fd;
short port;
struct sockaddr_in sin;
if(argc != 3)
{
usage((char *)argv[0]);
exit(1);
}
if((port = atoi(argv[2])) < 5000)
{
usage((char *)argv[0]);
exit(1);
}
/* 1 创建socket fd */
if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)//UDP编程
{
perror("socket");
exit(-1);
}
/* 2 连接服务器 */
/* 2.1 填充struct sockaddr_in结构体变量*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);//转为网络字节序端口号
#if 0
#else
if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
printf("UDP client starting ...... OK!
");
/* 3 读写*/
char buf[BUFSIZ];
while(1)
{
fprintf(stderr,"Please input the string to server:");
bzero(buf,BUFSIZ);
if(fgets(buf,BUFSIZ-1,stdin) == NULL)
{
perror("fgets");
continue;
}
sendto(fd,buf,strlen(buf),0,(struct sockaddr *)&sin,sizeof(sin));
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("client is existed!
");
break;
}
}
_error1:
close(fd);
return 0;
}
4.3,服务器端代码server.c
#include "net.h"
int main(int argc, const char *argv[])
{
int fd;
struct sockaddr_in sin;
/* 1 创建socket fd */
if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)//UDP编程,套接字类型为SOCK_DGRAM
{
perror("socket");
exit(-1);
}
/* 2 允许绑定地址快速重用 */
int b_reuse = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
/* 3 绑定 */
/* 3.1 填充struct sockaddr_in 结构体变量*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT);
#if 1
/* 让服务器可以绑定在任意的IP上*/
sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else
if(inet_pton(AF_INET,SERV_IP_ADDR,(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
/* 3.2 绑定*/
if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)))
{
perror("bind");
goto _error1;
}
printf("UDP server starting .... OK!
");
char buf[BUFSIZ];
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while(1)
{
/* 让系统自动获取客户端的信息*/
bzero(buf,BUFSIZ);
if(recvfrom(fd,buf,BUFSIZ-1,0,(struct sockaddr *)&cin,&addrlen) < 0)
{
perror("recvfrom");
continue ;
}
char cin_ipv4_addr[16];
if(inet_ntop(AF_INET,&cin.sin_addr.s_addr,cin_ipv4_addr,sizeof(cin_ipv4_addr)) < 0)
{
perror("inet_ntop");
goto _error1;
}
printf("Receive from (%s:%d),Data: %s",cin_ipv4_addr,ntohs(cin.sin_port),buf);
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("client (%s:%d) is existing!
",cin_ipv4_addr,ntohs(cin.sin_port));
}
}
_error1:
close(fd);
return 0;
}