首先回顾socket套接字编程:
socket就是一套网络编程接口:上层用户通过这些接口简单地完成网络通信传输不需要关心内部实现【类似中间件】
五元组:(源IP地址,源端口,目的IP地址,目的端口,协议),用于标识数据,每个网络中数据都会包含
套接字编程:使用socket接口实现通信
网络通信:
网络中两端主机上进程间通信,两端分别是客户端、服务器端
客户端:永远主动发送请求,发送前必须知道服务器端地址
服务器端:永远被动接收请求,告诉客户端自己的地址【通常是不变的】
注意:服务端socket只绑定服务器端主机上的IP地址,客户端也是只绑定自己主机上的IP
UDP网络通信
UDP【用户数据报协议】:无连接、不可靠、无序、有最大长度限制
由于UDP特性:操作系统接收到数据后判断目的地址信息,然后去内核中socket容器查找,找到就直接放在接收缓冲区,如果没找到会丢弃掉该数据
客户端流程
- 创建套接字——内核中创建socket结构体,向进程返回操作句柄。通过内核中socket结构体与网卡建立联系
- 绑定地址信息——为内核中创建的socket结构体添加地址描述信息(ip地址、端口)
- 发送数据——把数据先拷贝到内核中socket结构体的发送缓冲区,OS在需要时取出数据并对其进行封装,通过网卡发送出去
- 接收数据——从socket结构体的接收缓冲区取出数据,根据源IP、目的IP确认对端
- 关闭套接字,释放资源
服务器流程
- 创建套接字
- 绑定地址信息
- 接收数据
- 发送数据
- 关闭套接字,释放资源
实现
客户端:
#include <iostream>
#include <cstdio>
#include <string>
#include <unistd.h> //close接口
#include <stdlib.h> //atoi接口
#include <netinet/in.h> //地址结构定义
#include <arpa/inet.h> //字节序转换接口
#include <sys/socket.h> //套接字接口
class UdpSocket
{
public:
UdpSocket():_sockfd(-1)
{
}
//创建套接字
bool Socket()
{
_sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(_sockfd<0)
{
perror("socket error");
return false;
}
return true;
}
//绑定地址信息
bool Bind(const std::string &ip,uint32_t port)
{
//定义IPV4地址结构
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htonl(port);
addr.sin_addr.s_addr=inet_addr(ip.c_str());
//绑定地址
socklen_t len=sizeof(struct sockaddr_in);
int ret=bind(_sockfd,(struct sockaddr*)&addr,len)