UDP模拟实现

文章目录

  • 实现封装一个UDPSocket类
  • UDP服务端程序
  • UDP客户端程序
  • 尝试连接阿里云

实现封装一个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 
#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;
};

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对话交流

你可能感兴趣的:(Linux网络)