实现一个简单的英译汉的功能
备注:套接字的使用,在https://blog.youkuaiyun.com/Damn_Yang/article/details/88377815已经写过
封装UdpSocket
udp_socket.hpp
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cassert>
#include <string>
#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()
{
fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_ < 0)
{
perror("socket");
return false;
}
return true;
}
bool Close()
{
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");
return false;
}
return true;
}
bool RecvFrom(std::string* buf, std::string* ip = NULL, uint16_t* port = NULL)
{
char tmp[1024 * 10] = { 0 };
sockaddr_in peer;
socklen_t len = sizeof(peer);
ssize_t read_size = recvfrom(fd_, tmp, sizeof(tmp)-1, 0, (sockaddr*)&peer, &len);
if (read_size < 0)
{
perror("recvfrom");
return false;
}
// 将读到的缓冲区内容放到输出参数中
buf->assign(tmp, read_size);
if (ip != NULL)
{
*ip = inet_ntoa(peer.sin_addr);
}
if (port != NULL)
{
*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");
return false;
}
return true;
}
private:
int fd_;
};
UDP通用服务器
udp_server.hpp
#pragma once
#include "udp_socket.hpp"
// C 式写法
// typedef void (*Handler)(const std::string& req, std::string* resp);
// C++ 11 式写法, 能够兼容函数指针, 仿函数, 和 lamda
#include <functional>
typedef std::function<void (const std::string&, std::string* resp)> Handler;
class UdpServer {
public:
UdpServer()
{
assert(sock_.Socket());
}
~UdpServer()
{
sock_.Close();
}
bool Start(const std::string& ip, uint16_t port, Handler handler)
{
// 1. 创建 socket
// 2. 绑定端口号
bool ret = sock_.Bind(ip, port);
if (!ret)
{
return false;
}
// 3. 进入事件循环
for (;;)
{
// 4. 尝试读取请求
std::string req;
std::string remote_ip;
uint16_t remote_port = 0;
bool ret = sock_.RecvFrom(&req, &remote_ip, &remote_port);
if (!ret)
{
continue;
}
std::string resp;
// 5. 根据请求计算响应
handler(req, &resp);
// 6. 返回响应给客户端
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服务器进行通用接口的封装,基于以上封装,实现一个查字典的服务器就很容易了
dict_server.cc
#include "udp_server.hpp"
#include <unordered_map>
#include <iostream>
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;
}
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("c++", "最好的编程语言"));
g_dict.insert(std::make_pair("OK", "好的"));
// 2. 启动服务器
UdpServer server;
server.Start(argv[1], atoi(argv[2]), Translate);
return 0;
}
UDP通用客户端
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 和 端口号
std::string ip_;
uint16_t port_;
};
实现英译汉客户端
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;
if (!std::cin)
{
std::cout << "Good Bye" << std::endl;
break;
}
client.SendTo(word);
std::string result;
client.RecvFrom(&result);
std::cout << word << " 意思是 " << result << std::endl;
}
return 0;
}