/*实现封装一个UDPSocket类,向外提供方便的套接字操作接口
* bool Socket() 创建套接字
* bool Bind(std::string &ip,uint16_t port)
* bool Recv(std::string &buf,std::string &ip,uint16_t port)
* bool Send(std::string &buf,std::string &ip,uint16_t port)
* bool Close()*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define CHECK_RET(q) if((q)==false){return -1;}
class UDPSocket
{
public:
UDPSocket():_sockfd(-1)
{}
~UDPSocket()
{
close(_sockfd);
}
bool Socket()
{
//int socket(int domain, int type, int protocol);
_sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(_sockfd<0)
{
perror("socket error");
return false;
}
return true;
}
bool Bind(std::string &ip,uint16_t port)
{
struct sockaddr_in addr;
addr.sin_family=AF_INET;
//因为端口和地址都是要在网络上传输的,因此需要字节序转换
//uint32_t htonl(uint32_t hostlong);
//将32位的数据从主机字节序转换为网络字节序
//uint16_t htons(uint16_t hostshort);
//将16位的数据从主机字节序转换为网络字节序
//uint32_t ntohl(uint32_t netlong);
//将32位的数据从网络字节序转换为主机字节序
//uint16_t ntohs(uint16_t netshort);
//将16位的数据从网络字节序转换为主机字节序
addr.sin_port=htons(port);//port是两个字节的数据16位
//in_addr_t inet_addr(const char *cp);
//将字符串点分十进制IP地址转换为网络字节序IP地址
//char *inet_ntoa(struct in_addr in);
//通过网络字节序IP地址转换为字符串点分十进制IP地址
addr.sin_addr.s_addr=inet_addr(ip.c_str());
//int bind(int sockfd,struct sockaddr *addr,socklen_t addrlen);
socklen_t len=sizeof(struct sockaddr_in);
int ret=bind(_sockfd,(sockaddr*)&addr,len);
if(ret<0)
{
perror("bind error");
return false;
}
return true;
}
bool Recv(std::string &buf,std::string &ip,uint16_t &port)
{
//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
char tmp[4096]={0};
struct sockaddr_in addr;
socklen_t len=sizeof(struct sockaddr_in);
int ret=recvfrom(_sockfd,tmp,4096,0,(sockaddr*)&addr,&len);
if(ret<0)
{
perror("recv error");
return false;
}
buf.assign(tmp,ret);//ret表示实际接收的长度
ip=inet_ntoa(addr.sin_addr);
port=ntohs(addr.sin_port);
return true;
}
bool Send(std::string &buf,std::string &ip,uint16_t port)
{
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
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,buf.c_str(),buf.size(),0,(struct sockaddr*)&addr,len);
if(ret<0)
{
perror("send error");
return false;
}
return true;
}
bool Close()
{
if(_sockfd>=0)
{
close(_sockfd);
_sockfd=-1;
return true;
}
return false;
}
private:
int _sockfd;
};
#include "udpsocket.hpp"
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("./udp_srv ip port\n");
return -1;
}
std::string server_ip = argv[1];
uint16_t server_port = atoi(argv[2]);
UDPSocket sock;
CHECK_RET(sock.Socket());
CHECK_RET(sock.Bind(server_ip, server_port));
while(1) {
std::string client_ip;
uint16_t client_port;
std::string buf;
sock.Recv(buf, client_ip, client_port);
printf("client[%s:%d]--say:%s\n", client_ip.c_str(), client_port,
buf.c_str());
buf.clear();
printf("server say:");
fflush(stdout);
std::cin >> buf;
sock.Send(buf, client_ip, client_port);
}
sock.Close();
return 0;
}
#include "udpsocket.hpp"
int main(int argc,char* argv[])
{
if(argc!=3)
{
std::cout<<"./udp_client ip port"<<std::endl;
return -1;
}
std::string server_ip=argv[1];
uint16_t server_port=atoi(argv[2]);
UDPSocket sock;
CHECK_RET(sock.Socket());
while(1)
{
std::string buf;
std::cout<<"client say:";
fflush(stdout);
std::cin>>buf;
sock.Send(buf,server_ip,server_port);
buf.clear();
sock.Recv(buf,server_ip,server_port);
std::cout<<"server say:"<<buf<<std::endl;
}
sock.Close();
return 0;
}
scp udp_server root@47.94.***.***:/home/admin 通过公网IP远程传输服务器程序到阿里云服务器
root@47.94.***.***'s password:
udp_server 100% 15KB 256.8KB/s 00:00
./udp_server 172.24.43.47 9000 阿里云通过ifconfig查看ip并启动服务器
./udp_client 47.94.***.*** 9000 本地通过公网IP连接阿里云服务器端口对齐
以上完成便可以本地客户端与阿里云服务器进行简单的UDP对话交流