實現封裝一個UDPSocket類
/*實現封裝一個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 <iostream>
#include <string>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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;
};
UDP服務端程序
#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;
}
UDP客戶端程序
#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對話交流