标签搜索

目 录CONTENT

文章目录

网络编程套接字(二).md

小小城
2021-08-22 / 0 评论 / 0 点赞 / 2 阅读 / 4,545 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

网络编程套接字(二)

@[toc]

一、简单的UDP网络程序

  • 封装udp_socket
#pragma once
#include <cstdio>
#include <cstring>
#include <string>
#include <cassert>
#include <cstdlib>

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

typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;

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

    bool Socket()
    {
      //创建socket操作句柄fd
      fd_ = socket(AF_INET,SOCK_DGRAM,0);
      if(fd_ < 0)
      {
        perror("socket error");
        return false;
      }

      return true;
    }

    //关闭套节字
    bool Close()
    {
      close(fd_);
      return true;
    }

    //绑定端口、IP
    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());//把点分十进制类型的ip字符串转化为32位的IP地址
      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 RecvFrom(std::string* buf,std::string* ip = nullptr,uint16_t* port = nullptr)
    {
      //出参,由函数调用时填充
      char temp[1024 * 10] = {0};
      sockaddr_in peer;
      socklen_t len = sizeof(peer);

      ssize_t read_size = recvfrom(fd_,temp,sizeof(temp) -1,0,(sockaddr*)&peer,&len);
      if(read_size < 0)
      {
        perror("recvfrom is error");
        return false;
      }

      buf->assign(temp,read_size);

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

      return true;
    }

    //发送数据
    bool SendTo(const std::string& buf,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);

      ssize_t write_size = sendto(fd_,buf.data(),buf.size(),0,(sockaddr*)&addr,sizeof(addr));
      if(write_size < 0)
      {
        perror("sendto is error");
        return false;
      }

      return true;
    }
  private:
    int fd_;
};

  • udp_server.hpp
#pragma once
#include <functional>
#include "udp_socket.hpp"

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

class UdpServer
{
  public:
    UdpServer()
    {
      //在构造函数内部创建sock
      assert(sock_.Socket());
    }

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

    bool Start(const std::string& ip, uint16_t port,Handler handler)
    {
      printf("server is start!\n");

      //绑定端口号
      bool ret = sock_.Bind(ip,port);
      if(!ret)
      {
        return false;
      }

      //进入死循环,循环处理客户的请求,并计算响应返回结果
      while(1)
      {
        //读取客户端的请求
        std::string req;
        std::string remote_ip;
        uint16_t remote_port;

        bool ret = sock_.RecvFrom(&req,&remote_ip,&remote_port);
        if(!ret )
        {
          //如果读取失败尝试循环继续读取,不能直接退出
          continue;
        }
        
        //根据请求经过Handler计算响应,并返回结果
        std::string resp;
        handler(req,&resp);

        ret = sock_.SendTo(resp,remote_ip,remote_port);
        printf("[%s : %d] req: %s, resp: %s\n",remote_ip.c_str(),remote_port,req.c_str(),resp.c_str());
      }

      sock_.Close();
      return true;
    }

  private:
    UdpSocket sock_;
};

  • udp_client.hpp
#pragma once
#include "udp_socket.hpp"

class UdpClient
{
  public:
    UdpClient(const std::string& ip,uint16_t port)
      :ip_(ip)
       ,port_(port)
    {
      assert(sock_.Socket());
    }

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

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

    bool Sendto(const std::string& buf)
    {
      return sock_.SendTo(buf,ip_,port_);
    }

  private:
    UdpSocket sock_;
    
    //服务器端ip、port
    std::string ip_;
    uint16_t port_;
};

  • dict_server.cc
#include "udp_server.hpp"
#include <iostream>
#include <unordered_map>

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;
}

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

  g_dict.insert(std::make_pair("hello", "你好"));
  g_dict.insert(std::make_pair("world", "世界"));
  g_dict.insert(std::make_pair("c++", "最好的编程语言"));
  g_dict.insert(std::make_pair("bit", "特别NB"));

  UdpServer server;
  server.Start(argv[1],atoi(argv[2]),Translate);

  return 0;
}
#endif

int main()
{
  g_dict.insert(std::make_pair("world", "世界"));
  g_dict.insert(std::make_pair("c++", "最好的编程语言"));
  g_dict.insert(std::make_pair("bit", "特别NB"));
  g_dict.insert(std::make_pair("hello", "您好"));

  UdpServer server;
  server.Start("0.0.0.0",9090,Translate);

  return 0;
}

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

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

  UdpClient client(argv[1], atoi(argv[2]));

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

    client.Sendto(word);

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

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

0

评论区