博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux网络编程:基于UDP的程序开发回顾篇
阅读量:6981 次
发布时间:2019-06-27

本文共 4404 字,大约阅读时间需要 14 分钟。

基于无连接的UDP程序设计

       同样,在开发基于UDP的应用程序时,其主要流程如下:

 

       对于面向无连接的UDP应用程序在开发过程中服务端和客户端的操作流程基本差不多。对比面向连接的TCP程序,服务端少了listen和accept函数。前面我们也说过listen函数最主要的作用就是将一个socket套接字描述符转为被动监听模式,然后调用accept主要是用于等待客户端(用connect)来连接服务器。connect函数不仅可以用于流式套接字还可用于数据报式套接字。在TCP中,客户端调用connect函数会向服务器端触发一个TCP的3次握手过程,去建立一条TCP连接;而在UDP中,客户端调用该函数主要的作用是告诉后面将要调用的recvfrom函数,仅仅只接受在connect函数中指明的服务器发来的数据,这样当后面调用recvfrom时最后两个参数就可以置为NULL了。也就说对UDP编程来说,客户端调用connect是可选的:如果调用了connect函数,recvfrom就可以省掉最后两个参数;如果不调用connect则recvfrom必须指明从哪儿收数据。

       对于UDP的编程其实主要在数据的收发处理上,而面向无连接的UDP编程中收发数据用到的最多的函数就是recvfrom()和sendto(),其原型如下:

ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);ssize_t sendto(int s, const void *buf, size_t len, int flags, struct sockaddr *to, socklen_t tolen);

       recvfrom函数主要用于从s所指定的套接字中接收数据,并将其存储在buf所指向的缓冲区里。如果from参数不为NULL,那么其中便会携带消息发送端的地址信息,fromlen则指明了信息发送方地址信息结构体的大小。如果接收方对发送发的地址不感兴趣,将from和fromlen置为NULL即可。返回值:小于0,有错误;大于0,实际收到的字节数;等于0,对端主动关闭。

       sendto函数,主要是buf所指向的数据发送到套接字描述符s中,len为要发送的数据长度,to中存储了对端的地址信息,即数据该发往何处,tolen为to所占的字节数。返回值:小于0,有错误;大于0,实际发送的字节数。

      另外我们还知道,sendto是可以用于面向连接的流式套接字的,在TCP开发章节我们已经提过。这里在罗嗦一点,如果sendto用于面向流式的套接字编程中,to和tolen参数都会被忽略,如果发送数据时连接还未建立相应的提示错误为ENOTCONN。

      这里也没有哪个规定说是不准在TCP程序中用sendto,但我们一般都不这么做,自己体会一下就明白了,除非你的项目开发中有特殊需求必须用。一句话:记住sendto和recvfrom既可以用于面向连接的流式套接字中收发数据,也可以用于面向无连接的数据报式套接字。sendto()和recvfrom()一般用在面向无连接的数据报式套接字的程序开发中。

  UDP服务端代码, server.cpp 

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_MSG_SIZE 1024int main(int argc,char** argv){ int skfd,addrlen,ret; struct sockaddr_in addr,cltaddr; char buf[MAX_MSG_SIZE]={ 0}; char sndbuf[MAX_MSG_SIZE]={ 0}; //创建数据报式套接字skfd if(0>(skfd=socket(AF_INET,SOCK_DGRAM,0))){ perror("Create Error"); exit(1); } bzero(&addr,sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr=htonl(INADDR_ANY); addr.sin_port=htons(atoi(argv[1])); //将socket文件描述符skfd和本地端口和地址绑定起来 if(0>(bind(skfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in)))){ perror("Bind Error"); exit(1); } //开始收发数据 while(1){ ret=recvfrom(skfd,buf,MAX_MSG_SIZE,0,(struct sockaddr*)&cltaddr,&addrlen); if(ret < 0){ printf("recv data from %s:%d error!",inet_ntoa(cltaddr.sin_addr),ntohs(cltaddr.sin_port)); }else if(ret == 0){ perror("client has been closing socket!"); }else{ printf("From %s:%d,%s",inet_ntoa(cltaddr.sin_addr),ntohs(cltaddr.sin_port),buf); memset(sndbuf,0,MAX_MSG_SIZE); switch(buf[0]){ case 'a': strcpy(sndbuf,"After u ,lady..."); break; case 'b': strcpy(sndbuf,"Before u ,sir..."); break; case 'c': strcpy(sndbuf,"Can u?"); break; default: strcpy(sndbuf,"I dont't know what u want!"); } sendto(skfd,sndbuf,strlen(sndbuf),0,(struct sockaddr*)&cltaddr,addrlen); } memset(buf,0,MAX_MSG_SIZE); } return 0;}

 

  UDP客户端代码, client.cpp

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_MSG_SIZE 1024int main(int argc,char** argv){ int skfd,ret,len; struct sockaddr_in srvaddr; char buf[MAX_MSG_SIZE]={ 0}; char sndbuf[MAX_MSG_SIZE]={ 0}; struct in_addr addr; //创建数据报式套接字skfd if(0>(skfd=socket(AF_INET,SOCK_DGRAM,0))){ perror("Create Error"); exit(1); } if(0 == inet_aton(argv[1],&addr)){ perror("server addr invalid!"); exit(1); } bzero(&srvaddr,sizeof(struct sockaddr_in)); srvaddr.sin_family = AF_INET; srvaddr.sin_addr=addr; srvaddr.sin_port=htons(atoi(argv[2])); //我们的客户端只接收从服务器地址是srvaddr的主机发来的数据 if(0>(connect(skfd,(struct sockaddr*)&srvaddr,sizeof(struct sockaddr_in)))){ perror("Connect Error"); exit(1); } //开始收发数据 while(1){ memset(sndbuf,0,MAX_MSG_SIZE); len=read(0,sndbuf,MAX_MSG_SIZE); ret=sendto(skfd,sndbuf,strlen(sndbuf),0,(struct sockaddr*)&srvaddr,sizeof(struct sockaddr)); if(ret == len){ memset(buf,0,MAX_MSG_SIZE); //我们已经知道服务器地址信息了,所以最后两个参数为NULL ret=recvfrom(skfd,buf,MAX_MSG_SIZE,0,NULL,NULL); if(ret < 0){ perror("read error from server!"); }else if(ret == 0){ perror("server has been closing socket!"); }else{ buf[ret]='\0'; printf("From Server:%s\n",buf); } } } return 0;}

  测试结果:

      我们客户端接收用户命令行输入的指令,然后将其发给UDP服务器端;服务器端收到不同的指令后给客户端予以不同的提示信息,整个流程如上所示。

      udpclt.c的示例代码中我是调用了connect,勤奋好学的童鞋可以动手试验哈不调用connect然后将程序调通吧。

  转载自:

你可能感兴趣的文章
MagicLinux+MySQL5+PHP5+Apache2+phpMyAdmin
查看>>
服务器RAID磁盘坏道修复实战
查看>>
SOAP
查看>>
理解Windows中的路由表和默认网关
查看>>
MalformedInputException处理
查看>>
OPENAPI的测试用例编写方法
查看>>
事件通知(Event Notification)实践
查看>>
java json和object互换
查看>>
脚本语言程序员怎么学习程序设计?
查看>>
帮助电力,轻松实现运维管理
查看>>
网络嗅探软件全接触(2)
查看>>
J0ker的CISSP之路:复习-Information Security Management(4)
查看>>
SCOM 2007 R2监控系统安装部署(三)安装SCOM报表服务器和审计服务器
查看>>
分布式监控系统Zabbix-3.0.3-完整安装记录 - 添加shell脚本监控
查看>>
Redis中的关系查询(范围查询,模糊查询等...)
查看>>
Git常用命令总结【转】
查看>>
Android高级界面组件的学习(三)
查看>>
JVM 常量池理解
查看>>
【设计模式】—— 创建者模式Builder
查看>>
Phalcon入门教程之模型CURD(2)
查看>>