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 <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對話交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章