从一个图示开始:
从上述图示中我们都可以看到,UDP的传输相对来说比TCP传输的时候要简单很多,因为其不需要建立稳定连接,只是相互端口之间的发送,对于一些传输效率需求比较高的应用场景来说,是比较适合的,但是其在稳定性,可靠性上就有一定差异了
发送数据:
#include
ssize_t send(int sockfd,const void* buf,size_t nbytes,int flag);(调用connect过后可以直接调用send方法)
返回:成功返回发送字节数,出错返回-1
ssize_t sendto(int sockfd,const void * buf,size_t nbytes,int flag,const struct sockaddr * destaddr,socklen_t destlen);
返回:成功返回发送字节数,出错返回-1
ssize_t sendmsg(int sockfd,const struct msghdr *msg,int flag);
返回:成功返回发送字节数,出错返回-1
struct msghdr{
void *msg_name; /**/
socklen_t msg_namelen;/**/
struct iovec * msg_iov;/**/
int msgiovlen; /**/
void *msg_control;/**/
socklen_t msg_controllen;/**/
int msg_flag;/**/
}
接收数据
#include
ssize_t recv(int sockfd,void *buf,size_t nbytes,int flag);
ssize_t recvfrom(int sockfd,void * restrict buf,size_t len,int flag,struct sockaddr* restrict addr,socklen_t *restrict addrlen);
一般flag为0;
ssize_t recvmsg(int sockfd,struct msghdr *msg,int flag);
返回:返回消息的字节数,无消息返回0,出错返回-1
不多说上代码
/*
* ===========================================================================
*
* Filename: udp_server.c
* Description:
* 基于udp协议的一个server端的程序(udp协议没有差错校验)面向无连接的不可靠的协议
* Version: 1.0
* Created: 2017年05月13日 09时27分26秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int sockfd;
void sig_handler(int signo){
if(signo == SIGINT){
perror("sig interrupt and pid cancel");
exit(1);
close(sockfd);
}
}
void out_client_info(struct sockaddr_in *clientaddr){
char ip[16];
int port;
memset(ip,0,sizeof(ip));
inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));
port = ntohs(clientaddr->sin_port);
printf("client:%s(%d)\n",ip,port);
}
void do_service(){
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
char buff[1024];
memset(&clientaddr,0,len);
ssize_t size = recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&clientaddr,&len);
if(size < 0 ){
printf("recv error");
}else{
out_client_info(&clientaddr);
printf("client send info:%s\n",buff);
time_t t = time(0);
char *ptr = ctime(&t);
ssize_t time_size = strlen(ptr) * sizeof(char);
if(sendto(sockfd,ptr,time_size,0,(struct sockaddr*)&clientaddr,len) < 0){
perror("send to error");
}
}
}
int main(int argc,char *argv[]){
//确定绑定的端口,从命令行传入参数,第二个参数是绑定端口的参数
if(argc < 2){
printf("usage :%s port\n",argv[0]);
exit(EXIT_FAILURE);
}
if(signal(SIGINT,sig_handler) == SIG_ERR){
perror("signal sigint error");
exit(EXIT_FAILURE);
}
/* *
*创建socket
*
* */
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0 ){
perror("socket create error");
exit(EXIT_FAILURE);
}
int res;
int opt = 1;
/* *
*设置端口停止后,后续端口能够立马再次使用
* */
if((res = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))) <0){
perror("setsockopt error");
exit(1);
}
/* *
*调用bind函数对socket和地址进行绑定
sockaddr--->socket通用地址
sockaddr_in--->socket专用地址
* */
struct sockaddr_in addr_in;
memset(&addr_in,0,sizeof(addr_in));
addr_in.sin_family = AF_INET; //IPV4
addr_in.sin_port = htons(atoi(argv[1])); //端口必须要是网络字节序
addr_in.sin_addr.s_addr = INADDR_ANY; //获得主机上面所有ip地址的请求
if(bind(sockfd,(struct sockaddr *)&addr_in,sizeof(addr_in)) < 0){ //对端口进行绑定
perror("bind error");
exit(EXIT_FAILURE);
}
/* *
*
* */
while(1){
do_service();
}
return 0;
}
/*
* ===========================================================================
*
* Filename: udp_client.c
* Description: 基于udp协议的一个client端
* Version: 1.0
* Created: 2017年05月13日 10时09分41秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include
#include
#include
#include
#include
#include
#include
int client_sockfd;
int main(int argc,char * argv[]){
if(argc < 3){
printf("usage :%s ip port\n",argv[0]);
exit(EXIT_FAILURE);
}
client_sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(client_sockfd < 0 ){
perror("create client socket error");
exit(EXIT_FAILURE);
}
/**
*一般在客户端是不需要去进行绑定操作的,调用recv和sendto进行双向通信
*/
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET; //IPV4
serveraddr.sin_port = htons(atoi(argv[2]));//端口
inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr); //ip
/* *
*注意:如果在udp中调用connect的话,不会进行握手动作,只是在内核中去记住了地址信息,这个时候可以直接使用send去发送信息,而不需要再去进行调用sendto函数
调用connect的好处就是客户端接收到的数据报文仅仅是服务器发过来的,如果不去调用的话,则很有可能是其他服务器发过来的
*
* */
int connect_result;
connect_result = connect(client_sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
if(connect < 0){
perror("connect error");
exit(EXIT_FAILURE);
}
char buff[1024] = "helloworld";
ssize_t client_size_t;
client_size_t = sendto(client_sockfd,buff,sizeof(buff),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
if(client_size_t < 0){
perror("sendto error");
exit(1);
} else {
memset(buff,0,sizeof(buff));
size_t size;
size = recv(client_sockfd,buff,sizeof(buff),0);
if(size <0){
perror("recv error");
exit(EXIT_FAILURE);
}else{
printf("%s",buff);
}
}
close(client_sockfd);
return 0;
}
代码都是经过调试的,udp_server端负责去接收client发过来的报文信息.
由于最近个人事情比较多,所有很长一段时间都没有去更新了.
欢迎访问博客