网络 UDP协议(C++ |
您所在的位置:网站首页 › udp可靠的传输协议实现了吗 › 网络 UDP协议(C++ |
这里写目录标题
udp通信编程各端的操作流程:服务端操作流程:客户端操作流程:第2,3步与服务端不同
socket接口介绍udp客户服务端代码实现
推荐阅读
socket套接字编程就是在网络程序中编写代码,通过一套套的接字接口实现网络程序的编写。 udp通信编程udp是无连接、不可靠、面向数据报的传输层协议。 特点:支持多对多连接交互通信。尽最大努力交付,不保证可靠性,但速度最快 各端的操作流程: 服务端操作流程: 创建套接字端口:在内核中创建socket结构体,关联进程与网卡之间的联系为套接字绑定地址信息:网络通信中的数据都必须带有源端IP、源端端口、对端IP、对端端口、协议。在内核创建的socket结构体中描述IP地址端口以及协议,(必须主动绑定,告诉客户端自己的地址信息,如果不绑定客户端就不知道该发往哪个服务端了)为了告诉操作系统发往哪个IP地址,哪个端口的数据是交给我来处理的接收数据:告诉操作系统发往哪个地址和端口的数据应该交给我处理,操作系统一旦接收到发往这个地址和端口的数据,就会将这条数据放到对应的socket的接收缓冲区中,然后服务端从对应的socket的接收缓冲区中取出数据。发送数据:将数据写入内核中的socket发送缓冲区中,操作系统选择合适的时候将数据封装发送出去关闭套接字:释放资源 客户端操作流程:第2,3步与服务端不同 创建套接字:在内核中创建socket结构体,关联进程与网卡之间的联系为套接字绑定地址信息:描述在内核中创建的socket结构体的源端地址信息;发送的数据中源端地址信息就是绑定的地址信息(不推荐主动绑定地址,降低端口冲突的概率,从而确保数据发送的安全性)发送数据:将数据放到socket的发送缓冲区中,操作系统选择合适时候封装数据并发送数据。若socket发送数据的时候还没绑定地址,则操作系统会选择合适的地址进行绑定。接收数据:将数据写入内核中的socket发送缓冲区中,操作系统选择合适的时候将数据封装发送出去关闭套接字:释放资源 socket接口介绍1、创建套接字int socket(int domain, int type, int protocol) 参数内容(domian:地址域(本地通信-AF_LOCAL、IPv4-AF_INET、IPv6-AF_INET6等)确定本次socket通信使用哪种协议版本的地址结构,不同的协议版本有不同的地址结构;type:套接字类型(流式套接字-SOCK_STREAM、数据报套接字-SOCK_DGRAM等);protocol:协议类型(TCP-IPPROTO_TCP、UDP-IPPROTO_UDP) ,默认为0-流式默认TCP,数据报默认UDP) 返回值:文件描述符-非负整数, 套接字所有其他接口的操作句柄,失败返回-1 2、为套接字绑定地址信息int bind(int sockfd, struct sockaddr *addr, socklen_t len)参数内容(sockfd:创建套接字返回的操作句柄;addr:要绑定的地址信息;len:要绑定的地址信息长度) 中间的参数结构体有很多种 struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; struct sockaddr_in { sa_family sin_family;//地址域 in_port_t sin_port;//端口号 struct in_addr sin_addr;//IP地址 }; struct sockaddr_in6 { sa_family sin_family;//地址域 in_port_t sin6_port;//端口号 uint32_t sin6_flowinfo; struct in6_addr, sin6_addr;//IP地址 unit32_t sin6_scope_id; } struct sockaddr_un { __SOCKADDR_COMMON (sun_); char sun_path[108]; };不同的地址结构,有统一的一个信息:前两个字节是地址域类型,bind可以绑定不同的地址结构,为了实现接口统一,因此用户定义地址结构的时候,需要定义自己需要的地址结构,例如IPv4就使用struct sockaddr_in,但是进行绑定的时候,统一类型强转成为sockaddr*类型 简单解析bind接口的实现 bind(fd,addr, len) { if(addr->sa_family==AF_INET) { //绑定IPv4地址信息,这个结构体按照sockaddr_in进行解析 } else if (addr->sa_family==AF_INET6) { //绑定IPv6地址信息,这个结构体按照sockaddr_in6进行解析 } else if ... }3、接收数据,接收发送者地址便于回复ssize_t recvfrom(int sockfd, char *buf, int len, int flag, struct sockaddr *peer_addr, socklen *addrlen) 参数内容(sockfd:创建套接字返回的操作句柄;buf:一块缓冲区,用于接收从接收缓冲区中取出数据;len:想要接收的数据长度;flag:操作选项标志,默认为0,表示阻塞操作;peer_addr:发送方的地址信息;addrlen:想要获取的地址信息长度以及返回实际长度) 返回值:成功返回实际接收到的数据字节长度,失败返回-1 4、发送数据ssize_t sendto(int sockfd, char *data, int len, int flag, struct sickaddr *peer_addr, socklen_t addrlen) 参数内容(socket:socket操作句柄;data:要发送的数据地址;len:要发送数据长度;flag:默认为0,表示阻塞操作;peer_addr:接收方的地址信息;addrlen:地址信息长度) 返回值:成功返回实际发送的数据字节长度,失败返回-1 5、关闭套接字int close(int fd) 网络字节序的转换接口 uint32_t htonl(uint32_t hostlong) 主机字节序到网络字节序的转换 uint16_t htons(uint16_t hostshort) uint32_t ntohl(uint32_t netlong)网络字节序到主机字节序的转换 uint16_t ntohs(uint16_t netshort) in_addr_t inet_addr(const char *cp)将字符串的点分十进制IP地址转换成为网络字节序的整数IP地址 char *inet_ntoa(struct in_addr in)将网络字节序的整数IP地址转化为字符串点分十进制IP地址 const char *inet_ntop(int af, const void *src,char *dst, socklen_t size)将网络字节序的整数IP地址转化为字符串IP地址-兼容IPv4和IPv6 int inet_pton(int af, const char *src, void *dst)将字符串的IP地址转换成为网络字节序的整数IP地址-兼容IPv4和IPv6 udp客户服务端代码实现使用c++封装UdpSocket类,实例化的每一个对象都是一个udp通信套接字,并且能够通过成员接口实现udp通信流程 udpsocket.hpp //udpsocket.hpp #include #include #include #include #include #include using namespace std; class UdpSocket { public: UdpSocket() :_sockfd(-1) {} //创建套接字 bool Socket() { _sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (_sockfd //定义IPv4地址结构体 struct sockaddr_in addr; //地址信息赋值 addr.sin_family = AF_INET; addr.sin_port = htons(port);//将主机字节序短整型型数据转化为网络字节序数据 addr.sin_addr.s_addr = inet_addr(ip.c_str());//将字符串IP地址转化为网络字节序IP地址 socklen_t len = sizeof(struct sockaddr_in); int ret = bind(_sockfd, (struct sockaddr*)&addr, len); if (ret struct sockaddr_in peer_addr;//用于接收发送端的地址信息 socklen_t len = sizeof(struct sockaddr_in); char tmp[4096] = {0}; int ret = recvfrom(_sockfd, tmp, 4096, 0, (struct sockaddr*)&peer_addr, &len); if (ret *port = ntohs(peer_addr.sin_port);//网络字节序到主机字节序的转换 } if (ip != NULL) { *ip = inet_ntoa(peer_addr.sin_addr);//网络字节序到字符串IP地址的转换 } return true; } //发送数据 bool Send(const string &data, string &ip, const uint16_t port) { struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip.c_str()); socklen_t len = sizeof(struct sockaddr_in); int ret = sendto(_sockfd, data.c_str(), data.size(), 0, (struct sockaddr*)&addr, len); if (ret if (_sockfd > 0) { close(_sockfd); _sockfd = -1; } return true; } private: int _sockfd; };udp_srv.cpp #include #include #include "udpsocket.hpp" using namespace std; #define CHECK_RET(q) if((q)==false){return false;} int main(int argc, char *argv[]) { //运行时有三个参数 udp_src 192.168.73.29 4096 if (argc != 3) { cout if (argc != 3) { cout |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |