Linux网络编程:基于UDP的程序开发回顾篇
基于无连接的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 <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #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};//创建数据报式套接字skfdif(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 <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #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;//创建数据报式套接字skfdif(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);//我们已经知道服务器地址信息了,所以最后两个参数为NULLret=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然后将程序调通吧。
转载自:http://blog.chinaunix.net/uid-23069658-id-3276167.html
Linux网络编程:基于UDP的程序开发回顾篇相关推荐
- Linux网络编程 - 基于UDP的服务器端/客户端
一 理解UDP 1.0 UDP协议简介 UDP(User Datagram Protocol,用户数据报协议) [RFC 768] UDP协议的数据传输单元叫 UDP用户数据报,而TCP协议的数据传输 ...
- 【Linux网络编程】UDP 套接字编程
[Linux网络编程]UDP 套接字编程 [1]用户数据报协议(UDP) UDP是一个简单的传输层协议,不保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证每个数 ...
- 【网络编程】TCP 网络应用程序开发
[网络编程]TCP 网络应用程序开发 TCP 网络应用程序开发流程 1. TCP 网络应用程序开发流程的介绍 2. TCP 客户端程序开发流程的介绍 3. TCP 服务端程序开发流程的介绍 4. 小结 ...
- 嵌入式linux网络编程之——5年程序员给你深度讲解socket套接字
以下内容转载自 https://www.toutiao.com/i6827837032622981636/ 本文主要给大家分享网络七层概念之网络编程socket,前边的章节已经给大家讲述了链路层.物理 ...
- 【Linux网络编程】UDP编程
00. 目录 文章目录 00. 目录 01. 概述 02. UDP编程C/S结构 03. UDP常用函数 3.1 sendto函数 3.2 recvfrom函数 3.3 bind函数 04. 程序示例 ...
- 【Linux网络编程】UDP洪水攻击
00. 目录 文章目录 00. 目录 01. 洪水攻击概述 02. UDP洪水攻击原理分析 03. IP协议格式 04. UDP协议格式 05. 原始套接字 5.1 原始套接字概述 5.2 原始套接字 ...
- Linux网络编程 之 UDP编程(六)
目录 1. UDP客户端 核心函数 完整的UDP客户端程序 2. UDP服务端 核心函数 完整的UDP客户端程序 3. 总结 1. UDP客户端 核心函数 ssize_ ...
- Java网络编程——基于UDP协议的聊天室
UDP简述 UDP(User Datagram Protocol)协议是Internet 协议集支持的一个无连接的传输协议,中文名为用户数据报协议.它为应用程序提供了一种无需建立连接就可以发送封 ...
- Linux网络编程——基于tcp/ip的模拟聊天(文件传输)工具
开发平台:Linux 开发工具:Ubuntu, sourceInsight4.0 项目介绍: 本项目基于TCP/IP协议创建一个网络通信系统,可以实现客户之间的聊天通信以及文件传输,同时利用进程实现多 ...
最新文章
- 卡尔曼滤波(kalman)相关理论以及与HMM、最小二乘法关系 转
- STM32开发 -- STM32初识
- php开发者与composer的不得不说故事
- Cocos Creator导出场景和预制的问题
- LeetCode 1186. 删除一次得到子数组最大和(DP)
- Nest入门教程 - 初识控制器
- 数字图像处理--图像梯度算子的本质
- java中的step_Java中finalize()
- 如何解压.bz2文件包
- 通信用水泥杆和防腐木电杆在使用中有什么不同
- html5文字游戏引擎,HTML5游戏实战(3): 60行代码实现水平跑酷游戏
- ThreadLocal 常见使用场景
- scrapy爬取动态网页
- 问农事 - 菜蔬作物的节令
- html字体样式(2)
- 很有意境的语句[转]
- 高性价比降噪耳机推荐,2023年降噪耳机排行榜推荐
- matlab怎么调用filter函数,如何在matlab中建立和调用filter函数
- Linux下QT平台Mysql数据库开发环境配置
- 基因对疾病的影响规律--读论文