首页 资讯 应用 高压 设计 行业 低压 电路图 关于

通信网络

旗下栏目: 电力电子 通信网络 RFID LED

UDP浅析(客户-服务通信源码)

通信网络 | 发布时间:2018-06-10 | 人气: | #评论# | 本文关键字:UDP,协议
摘要:UDP协议的特点: 1,无连接,也就是说:UDP内部并没有维护端到端的状态,这跟TCP是不一样的。UDP不需要三次握手。 2,基于消息的数据传输服务,传输的是数据报,跟TCP基于字节流是不一样的

UDP协议的特点:1,无连接,也就是说:UDP内部并没有维护端到端的状态,这跟TCP是不一样的。UDP不需要三次握手。2,基于消息的数据传输服务,传输的是数据报,跟TCP基于字节流是不一样的,不会出现所谓的粘包问题,就是这些数据报是有边界的,而TCP是没有边界的。3,不可靠,表现在数据报可能会丢失,也可能会重复,也可能会乱序,缺乏流量控制。所以说:一般情况下,UDP是比TCP更加高效的。

有些场合更适合使用UDP,使用UDP编写的一些常见的应用程序有:DNS(域名系统),NFS(网络文件系统)和SNMP(简单网络管理协议)

基本模型:

也是需要服务端和客户端的服务端创建socket,bind,接下来调用recvfrom(因为不需要建立连接)一直阻塞,直到收到来自客户的数据对于客户端而言:创建socket,接下来也是直接调用sendto函数给服务器发送数据报,其中必须指定目的地(即服务器)的地址作为参数,这时recvfrom才会收到数据,并且对数据进行处理,recvfrom将与所接受的数据报一道返回客户的协议地址,因此服务器可以把响应发送给正确的客户。服务器这时会调用sendto函数,然后返回,客户端调用recvfrom接受,最后调用close函数

UDP的简单回射客户/服务器

1.png

当然,这里面需要用到recvfrom,sendto函数,我们来看看:

  1. #include <sys/types.h>  

  2. #include <sys/socket.h>  

  3. size_t recv(int sockfd, void *buf, size_t len, int flags);  

  4. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,  

  5. struct sockaddr *src_addr, socklen_t *addrlen);  

  6. ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);  

  7. //第一个:套接字socket  

  8. //第二个:缓冲区  

  9. //第三个:接收的长度  

  10. //第四个:flags,我们用0来表示  

  11. //第五个,第六个:指定对方的地址信息  

UDP服务端:

  1. #include <sys/types.h>  

  2. #include <sys/socket.h>  

  3. #include <stdlib.h>  

  4. #include <stdio.h>  

  5. #include <errno.h>  

  6. #include <netinet/in.h>  

  7. #include <sys/socket.h>  

  8. #include <arpa/inet.h>  

  9. #include <string.h>  

  10. #define ERR_EXIT(m)\  

  11.     do\  

  12.     {\  

  13.         perror(m);\  

  14.         exit(EXIT_FAILURE);\  

  15.     }while(0)  

  16. void echo_srv(int sock)  

  17. {  

  18.     char recvbuf[1024] = {0};  

  19.     struct sockaddr_in peeraddr;  

  20.     socklen_t peerlen;  

  21.     int n;                      //接受到的字节数  

  22.     while(1)  

  23.     {  

  24.         peerlen = sizeof(peeraddr);  

  25.         memset(recvbuf, 0, sizeof(recvbuf));  

  26.         n = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*)&peeraddr, &peerlen);  

  27.         if(n == -1)  

  28.         {  

  29.             if(errno == EINTR)  

  30.                 continue;  

  31.             ERR_EXIT("recvfrom");     

  32.         }  

  33.   

  34.         else if(n > 0)  

  35.         {  

  36.             fputs(recvbuf, stdout);  

  37.             sendto(sock, recvbuf, n, 0, (struct sockaddr*)&peeraddr, peerlen);        

  38.         }  

  39.     }  

  40.   

  41.     close(sock);  

  42. }  

  43. int main(void)  

  44. {  

  45.     //UDP通信的第一步创建一个套接字  

  46.     int sock;  

  47.     if((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)  

  48.         ERR_EXIT("socket");  

  49.     struct sockaddr_in servaddr;  

  50.     memset(&servaddr, 0, sizeof(servaddr));  

  51.     servaddr.sin_family = AF_INET;  

  52.     servaddr.sin_port = htons(5188);  

  53.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  

  54.     //INADDR_ANY本机的任意地址  

  55.     if(bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)  

  56.         ERR_EXIT("bind");  

  57.     echo_srv(sock);  

  58.     return 0;  

  59. }  

UDP客户端:

#include <sys/types.h>  

  1. #include <sys/socket.h>  

  2. #include <stdlib.h>  

  3. #include <stdio.h>  

  4. #include <errno.h>  

  5. #include <netinet/in.h>  

  6. #include <sys/socket.h>  

  7. #include <arpa/inet.h>  

  8. #include <string.h>  

  9. #define ERR_EXIT(m)\  

  10.     do\  

  11.     {\  

  12.         perror(m);\  

  13.         exit(EXIT_FAILURE);\  

  14.     }while(0)  

  15.   

  16. void echo_cli(int sock)  

  17. {  

  18.     struct sockaddr_in servaddr;  

  19.     memset(&servaddr, 0, sizeof(servaddr));  

  20.     servaddr.sin_family = AF_INET;  

  21.     servaddr.sin_port = htons(5188);  

  22.     servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  

  23.     char sendbuf[1024] = {0};  

  24.     char recvbuf[1024] = {0};  

  25.     while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)  

  26.     {  

  27.             sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));  

  28.             recvfrom(sock, recvbuf, sizeof(recvbuf), 0, NULL, NULL);  

  29.             //表示对等方的地址可以不要了  

  30.             fputs(recvbuf, stdout);  

  31.             memset(sendbuf, 0, sizeof(sendbuf));  

  32.             memset(recvbuf, 0, sizeof(recvbuf));  

  33.     }  

  34.     close(sock);  

  35. }  

  36. int main(void)  

  37. {  

  38.     //UDP通信的第一步创建一个套接字  

  39.     int sock;  

  40.     if((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)  

  41.         ERR_EXIT("socket");  

  42.     echo_cli(sock);  

  43.     return 0;  

  44. }  

那么客户端的地址,是在什么时候绑定的呢?是在第一次sendto的时候,因为我们前面已经知道了我客户端要跟谁(服务端)连接,我sendto的时候,会将服务端的信息加入到socket,所以我们调用sendto的时候,也就间接的知道啦跟谁进行连接,socket的结构体中:是知道客户端/服务端的端口号,IP地址套接口:

两个属性:本地地址(通过getsockname来获取),远程地址(通过getpeername来获取)(前提是:这个套接字是一个已连接套接字)当前我们的套接字是一个未连接的套接字,那么我们就可以通过getsockname来获取本地地址,也就是说:对于客户端,我们的本地地址不是通过bind函数来进行绑定的,我们是通过sendto函数来绑定的,第一次调用的时候就会绑定,接下来的操作调用是不会再去绑定的,因为我们不会去做多余的操作。如上,就是我们的UDP通信的过程。

注意点:

 

责任编辑:协议
首页 | 电气资讯 | 应用技术 | 高压电器 | 电气设计 | 行业应用 | 低压电器 | 电路图 | 关于我们 | 版权声明

Copyright 2017-2018 电气自动化网 版权所有 辽ICP备17010593号-1

电脑版 | 移动版 原创声明:本站大部分内容为原创,转载请注明电气自动化网转载;部分内容来源网络,如侵犯您的权益请发送邮件到[email protected]联系我们删除。