网络编程套接字(三)

网络编程套接字(三)

一、实现简单的Tcp服务器(单用户)

  • tcp_socket.hpp
#pragma once
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <string>

#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>

typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;

#define CHECK_RET(exp) if(!(exp)){\
    return false;\
}

class TcpSocket
{
  public:
    TcpSocket()
      :fd_(-1)
    {}

    TcpSocket(int fd)
      :fd_(fd)
    {}

    bool Socket()
    {
      fd_ = socket(AF_INET,SOCK_STREAM,0);
      if(fd_ < 0)
      {
        perror("socket is error");
        return false;
      }

      printf("socket fd is successful! fd = %d\n",fd_);
      return true;
    }

    bool Close()
    {
      printf("close fd! fd = %d ",fd_);
      close(fd_);
      return true;
    }

    bool Bind(const std::string& ip,uint16_t port)
    {
      sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      addr.sin_port = htons(port);

      int ret = bind(fd_,(sockaddr*)&addr,sizeof(addr));
      if(ret < 0)
      {
        perror("bind is error");
        return false;
      }

      return true;
    }

    bool Listen(int num = 5)
    {
      int ret = listen(fd_,num);
      if(ret < 0)
      {
        perror("listen is error");
        return false;
      }

      return true;
    }

    bool Accept(TcpSocket* peer,std::string* ip = nullptr,uint16_t* port = nullptr)
    {
      sockaddr_in peer_addr;
      socklen_t len = sizeof(peer_addr);

      int new_sock = accept(fd_,(sockaddr*)&peer_addr,&len);
      if(new_sock < 0)
      {
        perror("accept is error");
        return false;
      }

      printf("accept new fd! fd = %d\n",new_sock);

      peer->fd_ = new_sock;

      if(ip != nullptr)
      {
        *ip = inet_ntoa(peer_addr.sin_addr); 
      }
      if(port != nullptr)
      {
        *port = ntohs(peer_addr.sin_port);
      }

      return true;
    }

    int Recv(std::string* buf)
    {
      buf->clear();
      char temp[1024 * 10]= {0};
      
      ssize_t  read_size = recv(fd_,temp,sizeof(temp),0);
      if(read_size < 0)
      {
        perror("recv is error");
        return -1;
      }
      if(read_size == 0)
      {
        return 0;
      }

      buf->assign(temp,read_size);
      return 1;
    }
    
    bool Send(const std::string& buf)
    {
      ssize_t write_size = send(fd_,buf.data(),buf.size(),0);
      if(write_size < 0)
      {
        perror("send is error");
        return false;
      }
      return true;
    }

    bool Connect(const std::string& ip,uint16_t port)
    {
      sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      addr.sin_port = htons(port);

      int ret = connect(fd_,(sockaddr*)&addr,sizeof(addr));
      if(ret < 0)
      {
        perror("connect is error");
        return false;
      }
      return true;
    }

    int GetFd()
    {
      return fd_;
    }
  private:
    int fd_;
};

  • tcp_server.hpp
#pragma once
#include <functional>
#include "tcp_socket.hpp"

typedef std::function<void (const std::string& req, std::string* resp)> Handler;

class TcpServer 
{
  public:
    TcpServer(const std::string ip,uint16_t port)
      :ip_(ip)
       ,port_(port)
    {}

    bool Start(Handler handler)
    {
      //1.创建socket
      CHECK_RET(listen_sock_.Socket());

      //2.绑定端口号
      CHECK_RET(listen_sock_.Bind(ip_,port_));

      //3.进行监听
      CHECK_RET(listen_sock_.Listen());
      
      //4.进入死循环处理事件
      //
      while(1)
      {
        //5.进行accept
        TcpSocket new_sock;
        std::string ip;
        uint16_t port;

        if(!listen_sock_.Accept(&new_sock,&ip,&port))
        {
          continue;
        }

        printf("[client %s : %d ]connect!",ip.c_str(),port);

        //6.进行循环读取
        while(1)
        {
          //7.读取请求
          std::string req;
          int ret = new_sock.Recv(&req);
          if(ret < 0)
          {
            printf("[client %s : %d]disconnect!\n",ip.c_str(),port);
            continue;
          }
          if(ret == 0)
          {
            printf("[client %s : %d]关闭了链接!\n",ip.c_str(),port);
            new_sock.Close();
            break;
          }

          printf("client say : [%s : %d]\n",ip.c_str(),port);

          //8.计算响应
          std::string resp;
          handler(req,&resp);

          //9.写回响应
          new_sock.Send(resp);

          printf("[%s:%d] req: %s, resp: %s\n", ip.c_str(), port,
              req.c_str(), resp.c_str());
          
        }
      }
      return true;
    }

  private:
    TcpSocket listen_sock_;

    std::string ip_;
    uint16_t port_;
};

  • tcp_client.hpp
#pragma once
#include "tcp_socket.hpp"

class TcpClient 
{
  public:
    TcpClient(const std::string& ip, uint16_t port) : ip_(ip), port_(port) 
   {
      // [注意!!] 需要先创建好 socket
      sock_.Socket();
      //
    }

    ~TcpClient() 
    {
      sock_.Close();
    }

    bool Connect() 
    {
      return sock_.Connect(ip_, port_);
    }

    bool Recv(std::string* buf) 
    {
      return sock_.Recv(buf);
    }

    bool Send(const std::string& buf) 
    {
      return sock_.Send(buf);
    }

  private:
    TcpSocket sock_;
    std::string ip_;
    uint16_t port_;

};

  • dict_server.cc
#include <unordered_map>
#include "tcp_server.hpp"

std::unordered_map<std::string, std::string> g_dict;

void Translate(const std::string& req, std::string* resp) 
{
  auto it = g_dict.find(req);
  if (it == g_dict.end()) 
  {
    *resp = "未找到";
    return;
  }

  *resp = it->second;
  return;
}

#if 0
int main(int argc, char* argv[]) 
{
  if (argc != 3) 
  {
    printf("Usage ./dict_server [ip] [port]\n");
    return 1;
  }
  
  // 1. 初始化词典
   g_dict.insert(std::make_pair("hello", "你好"));
   g_dict.insert(std::make_pair("world", "世界"));
   g_dict.insert(std::make_pair("bit", "贼NB"));

   // 2. 启动服务器
    TcpServer server(argv[1], atoi(argv[2]));
    server.Start(Translate);

    return 0;
   //
}
#endif

int main() 
{
  
  // 1. 初始化词典
   g_dict.insert(std::make_pair("hello", "你好"));
   g_dict.insert(std::make_pair("world", "世界"));
   g_dict.insert(std::make_pair("bit", "贼NB"));

   // 2. 启动服务器
    TcpServer server("0.0.0.0",9090);
    server.Start(Translate);

    return 0;
   //
}

  • dict_client.cc
#include "tcp_client.hpp"
#include <iostream>

int main(int argc, char* argv[]) 
{
  if (argc != 3) 
  {
    printf("Usage ./dict_client [ip] [port]\n");
    return 1;
  }

  TcpClient client(argv[1], atoi(argv[2]));
  bool ret = client.Connect();
  if (!ret) 
  {
    return 1;
  }

  for (;;) 
  {
    std::cout << "请输入要查询的单词:" << std::endl;
    std::string word;
    std::cin >> word;

    client.Send(word);
    std::string result;
    client.Recv(&result);
    std::cout <<word<<" 意思是:"<< result << std::endl;
  }
return 0;
}

在这里插入图片描述
在这里插入图片描述

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页