tcpsocket / udpsocket

/*封装一个tcpsocket类向外提供简单接口,能够实现客户端服务端编程流程*/
/*1.创建套接字 2.绑定地址信息 3.开始监听/发起连接请求 4获取已完成链接 5发送数据 6接收数据 7关闭套接字*/
#include 
#include 
#include 
#include 
#include 
#include 
#define CHECK_RET(q) if((q) == false){return -1;}
class TcpSocket
{
  public:
    TcpSocket()
      :_sockfd(-1)
    {}
    ~TcpSocket(){
      Close();
    }
    bool Socket()
    {
      _sockfd = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
      if(_sockfd < 0)
      {
        std::cerr << "scoket error\n";
        return false;
      }
      return true;
    }
    bool Bind( std::string &ip,uint16_t port)
    {
      struct sockaddr_in addr;
      addr.sin_family  = AF_FILE;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(&ip[0]);
      socklen_t len = sizeof(struct sockaddr_in);
      int ret = bind(_sockfd , (struct sockaddr*)&addr , len);
      if(ret <0 )
      {
        std::cerr << "bind error\n";
        return false;
      }
      return true;
    }

    bool Listen(int backlog = 5)
    {
      int ret = listen(_sockfd , backlog);
      if(ret < 0 )
      {
        std::cerr << "listen error\n";
        return false;
      }
      return true;
    }

    bool Connect(const std::string &ip , uint16_t port)
    {
      int ret;
      struct sockaddr_in addr;
      addr.sin_family = AF_FILE;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(&ip[0]);
      socklen_t len = sizeof(struct sockaddr_in);
      ret = connect(_sockfd , (struct sockaddr*)&addr , len);
      if(ret < 0)
      {
        std::cerr << "connect error\n";
        return false;
      }
      return true;
    }

    void SetFd(int fd)
    {
      _sockfd = fd;
    }

    int GetFd(int _sockfd)
    {
      return _sockfd;
    }

    bool Accept(TcpSocket &newsock)
    {
      struct sockaddr_in addr;
      socklen_t len = sizeof(struct sockaddr_in);
      //accept是一个阻塞函数;
      //当已完成连接队列中没有新连接的时候就会阻塞
      int fd = accept(_sockfd , (struct sockaddr*)&addr , &len);
      if(fd < 0)
      {
        std::cerr << "accept error\n";
        return false;
      }
      //接收一般发生在服务端,获取一个新的链接,若获取失败则应获取下一个不应退出.
      newsock.SetFd(fd);
      return true;
    }
    bool Send(std::string &buf)
    {
      int ret = send(_sockfd , &buf[0] , buf.size() , 0);
      //0为阻塞操作,当发送缓冲区满了后阻塞
      if(ret < 0)
      {
        std::cerr << "send error\n";
        return false;
      }
      return true;
    }
    bool Recv(std::string &buf)
    {
      //recv返回值为0不是为了表示返回值没有数据,而是为了表示链接断开(没有数据会阻塞)
      char tmp[4096] = {0};
      int ret = recv(_sockfd , tmp , 4096 , 0);
      if(ret < 0)
      {
        std::cerr << "recvfrom error\n";
        return false;
      }
      else if (ret == 0)
      {
        std::cerr << "peer shutdown\n";
        return false;
      }
      buf.assign(tmp, ret);
      return true;
    }

    bool Close()
    {
      if(_sockfd >= 0)
      {
        close(_sockfd);
        _sockfd = -1;
      }
      return true;
    }
  private:
    int _sockfd;
};
/*   描    述:传输层基于UDP协议的服务端程序
*   *       1.  创建套接字
*   *       2.  为套接字绑定地址信息
*   *       3.  接收数据
*   *       4.  发送数据
*   *       5.  关闭套接字
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc , char *argv[])
{
  if(argc != 3)
  {
    printf("Usage:./main 192.168.115.129 9000\n");
    return -1;
  }
  int sockfd = socket(AF_FILE , SOCK_DGRAM , IPPROTO_UDP);
  if(sockfd <0 )
  {
    perror("socket error");
    return -1;
  }
  struct sockaddr_in addr;//定义一个IPV4的地址结构
  addr.sin_family = AF_INET;
  //端口绑定
  addr.sin_port = htons(atoi(argv[2]));
  //IP地址绑定 inet将一个点分十进制IP地址转换为网络字节序的IP地址
  addr.sin_addr.s_addr = inet_addr("192.168.115.129");
  socklen_t len = sizeof(struct sockaddr_in);
  int ret = bind(sockfd , (struct sockaddr*)&addr, len);
  if(ret < 0)
  {
    perror("bind error");
    return -1;
  }
  while(1)
  {
    //接收数据
    char buf[1024] = {0};
    struct sockaddr_in cliaddr;
    len = sizeof(struct sockaddr_in);
    int ret = recvfrom(sockfd , buf , 1023 , 0 , 
        (struct sockaddr*)&cliaddr ,&len);
    if(ret < 0)
    {
      perror("recvfrom error\n");
      close(sockfd);
      return -1;
    }
    printf("client say : %s\n", buf);
    //sendto
    len = sizeof(struct sockaddr_in);
    memset(buf , 0x00 , 1024);
    scanf("%s" , buf);
    ret = sendto(sockfd , buf , strlen(buf) , 0 , 
        (struct sockaddr*)&cliaddr ,len);
    if(ret < 0 )
    {
      perror("sendto error");
      close(sockfd);
      return -1;
    }
  }
  close(sockfd);
}

/*封装实现一个udpsocket类 ; 向外提供更加容易使用的udp接口来实现udp通信流程*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define CHECK_RET(q) if((q) ==false ){return false;}
class UdpSocket
{
  public:
    UdpSocket()
      :_sockfd(-1)
    {}
    ~UdpSocket()
    {
      Close();
    }
    bool Socket()
    {
      _sockfd = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP);
      if(_sockfd < 0)
      {
        std::cerr << "socket error\n";
        return false;
      }
      return true;
    }
    bool Bind(const std::string &ip , uint16_t port)
    {
      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 = bind(_sockfd , (struct sockaddr*)&addr , len);
      if(ret < 0)
      {
        std::cerr << "bind error\n";
        return false;
      }
      return true;
    }//给一个字符Ip
    bool Recv(std::string &buf , std::string &ip , uint16_t &port)
    {
      char tmp[4096];
      struct sockaddr_in peeraddr;//对端地址
      socklen_t len = sizeof(peeraddr);
      int ret = recvfrom(_sockfd , tmp , 4096 , 0 , (struct sockaddr*)&peeraddr, &len);
      if(ret < 0)
      {
        std::cerr << "recvfrom error\n";
        return false;
      }
      buf.assign(tmp , ret);//开辟空间从tmp拷贝ret长的数据到buf中
      port = ntohs(peeraddr.sin_port);
      ip = inet_ntoa(peeraddr.sin_addr);//inet_ntoa返回一个字符串的首地址 , 它是一个非线程安全的接口 
      //它将网络字节序的整数IP地址转换为字符串IP地址
      return true;
    }
    bool Send(std::string &data , std::string &ip , uint16_t port)
    {
      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 , &data[0] , data.size() , 0 , (struct sockaddr*)&addr , len);
      if(ret < 0 )
      {
        std::cerr << "sendto error\n";
        return -1;
      }
      return true;
    }
    bool Close()
    {
      if(_sockfd >= 0 )
      {
        close(_sockfd);
        _sockfd = -1;
      }
      return true;

    }
  private:
    int _sockfd;
};

int main(int argc , char *argv[])
{
  if(argc != 3)
  {
    std::cout << "./udp_cli serverip serverport\n";
    return -1;
  }
  std::string srv_ip = argv[1];
  uint16_t srv_port = atoi(argv[2]);
  UdpSocket sock;
  
  CHECK_RET(sock.Socket());
//  CHECK_RET(sock.Bind("192.168.115.129" , 8000));
  while(1)
  {
    std::string buf;
    std::cin >> buf;
    CHECK_RET(sock.Send(buf ,srv_ip, srv_port));
    buf.clear();
    CHECK_RET(sock.Recv(buf ,srv_ip, srv_port));
    std::cout << "server sat:" << buf << "\n";
  }
  CHECK_RET(sock.Close());
  return 0;
}

#include 
#include "tcpsocket.hpp"

int main(int argc, char *argv[])
{ 
  if(argc != 3)
  {
    std::cout << "./tcp_cli srvip srvport\n";
    return -1;
  }
  std::string ip = argv[1];
  uint16_t port = atoi(argv[2]);
  TcpSocket sock;
  //创建套接字
  CHECK_RET(sock.Socket());
  //绑定地址信息(客户端不需要主动绑定)
  //向服务端发起连接请求
  CHECK_RET(sock.Connect(ip, port));
  while(1)
  {
    std::string buf;
    std::cin >> buf;
    bool ret = sock.Send(buf);
    if(ret == false)
    {
      return -1;
    }

    buf.clear();
    ret = sock.Recv(buf);
    if(ret == false)
    {
      return -1;
    }
    std::cout << "server say:" << buf << "\n";
  }
  //发送数据
  //接收数据
  //关闭套接字
  sock.Close();
  return 0;
}

#include 
#include 
#include 
#include "tcpsocket.hpp"
#include 

void sigcb(int signo)
{
  //SIGCHLD信号是一个非可靠信号, 多个进程同时退出可能会导致时间丢失, 导致有可能会有僵尸进程没有被处理
  //因此在一次事件回调中将能够处理的僵尸进程全部处理掉
  while(waitpid(-1 , NULL , WNOHANG) > 0);
}

int main(int argc , char* argv[])
{
  //创建套接字
  //绑定地址信息
  //开始监听
  //获取已完成链接
  //接收数据
  //发送数据
  //关闭套接字
  if(argc != 3)
  {
    std::cout << "./tcp_srv 192.168.115.129 9000\n";
    return -1;
  }
  signal(SIGCHLD , sigcb);
  std::string ip = argv[1];
  uint16_t port = atoi(argv[2]);
  TcpSocket lst_sock;

  CHECK_RET(lst_sock.Socket());
  CHECK_RET(lst_sock.Bind(ip , port));
  CHECK_RET(lst_sock.Listen());

  TcpSocket newsock;
  while(1)
  {
    bool ret = lst_sock.Accept(newsock);
    if (ret == false)
    {
      continue;
    }
    //创建子进程进行任务处理
    //任务分摊----每个进程只负责一个任务(主进程负责新连接获取,子进程负责与客户端进行同行)
    //稳定性高---子进程出问题不会影响到主进程服务器
    if(fork() == 0)
    {
      while(1)
      {
        std::string buf;
        ret = newsock.Recv(buf);
        if(ret == false)
        {
          newsock.Close();
          continue;
        }
        std::cout << "client say:" << buf << "\n";

        buf.clear();
        std::cin >> buf;
        newsock.Send(buf);
      }
      newsock.Close();
      exit(0);
    }
    newsock.Close();
  }

  lst_sock.Close();
  return 0;
}

你可能感兴趣的:(tcpsocket / udpsocket)