简单的UDP网络程序———实现一个简单的英译汉功能

实现一个简单的英译汉的功能

备注:套接字的使用,在https://blog.csdn.net/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;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值