您的位置:首页 > 游戏 > 游戏 > 专业建设要素_久久建筑网登录入口_软文营销定义_常用的关键词挖掘工具有哪些

专业建设要素_久久建筑网登录入口_软文营销定义_常用的关键词挖掘工具有哪些

2024/10/5 12:40:26 来源:https://blog.csdn.net/china_chk/article/details/142493041  浏览:    关键词:专业建设要素_久久建筑网登录入口_软文营销定义_常用的关键词挖掘工具有哪些
专业建设要素_久久建筑网登录入口_软文营销定义_常用的关键词挖掘工具有哪些

一、本篇重点

对于上一篇实现的简单udp客户端/服务器进一步的补充改造,继续了解与Socket api的相关接口

二、upd服务器(第一版)

上一篇我们通过一边实现一个简单udp,一边学习Socket编程的相关接口,本篇打算进一步对上一篇的代码进行补充和添加功能,上一篇为了了解接口,只是简单的让client端能够发送消息到server端,然后server端获取消息并能够发送回来即可,这里先提供完整的代码。

1. udp_server.hpp

#pragma once#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include "errno.hpp"
#include <cstring>namespace chk
{const static uint16_t default_port = 8080;class UdpServer{public:// 对成员变量完成初始化UdpServer(uint16_t port = default_port) : _port(port){std::cout << "server port: " << _port << std::endl;}void Init() // 创建出套接字,并绑定端口号和ip{// 1. 创建套接字_sock = socket(AF_INET, SOCK_DGRAM, 0);if (_sock < 0){std::cerr << "create socket error: " << strerror(errno) << std::endl;exit(SOCKET_ERR);}std::cout << "bind socket success: " << _sock << std::endl; // 3// 2. 构建struct sockaddr_in结构体struct sockaddr_in local;bzero(&local, sizeof(local));       // 初始化local.sin_family = AF_INET;         // IPv4local.sin_port = htons(_port);      // 端口号local.sin_addr.s_addr = INADDR_ANY; // 服务器下的ip// 3. 绑定套接字和sockaddr_inint n = bind(_sock, (struct sockaddr *)&local, sizeof(local));if (n < 0){std::cerr << "bind error: " << strerror(errno) << std::endl;exit(BIND_ERR);}std::cout << "bind socket success: " << _sock << std::endl;}void Start() // 时刻读取套接字中的信息数据,并将其返回{char buffer[1024];while(true){// 收数据struct sockaddr_in peer;socklen_t len = sizeof(peer);int n = recvfrom(_sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);if(n>0) buffer[n] = '\0';else continue;//收到信息后打印出来:对方ip+端口号+内容std::cout << inet_ntoa(peer.sin_addr) << " - " << ntohs(peer.sin_port) << " : " << buffer << std::endl;// 发回去sendto(_sock,buffer,strlen(buffer),0,(struct sockaddr*)&peer,sizeof(peer));}}~UdpServer() // 析构{}private:int _sock;uint16_t _port;};
}

2. udp_server.cc

#include"udp_server.hpp"
#include<string>
#include<memory>
#include<cstdio>using namespace std;
using namespace chk;// 我们最终希望以 ./udp_server port 的形式去启动
static void usage(string proc)//使用手册
{std::cout << "Usage:\n\t" << proc << " port\n" << std::endl;
}int main(int argc,char* argv[])
{if(argc != 2){usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);unique_ptr<UdpServer> usvr(new UdpServer(port));usvr->Init();usvr->Start();return 0;
}

3. udp_client.hpp

#pragma once#include<iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<cstring>
#include<string>
#include"errno.hpp"

4. udp_client.cc

#include"udp_client.hpp"//基本要用到的头文件
using namespace std;static void usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " serverip serverport\n" << std::endl; 
}// ./udp_client server_ip server_port
int main(int argc,char* argv[])
{if(argc != 3){usage(argv[0]);exit(USAGE_ERR);}string server_ip = argv[1];uint16_t server_port = atoi(argv[2]);//1. 创建套接字int sock = socket(AF_INET,SOCK_DGRAM,0);if(sock < 0){cerr << "client : create socket error" << endl;exit(SOCKET_ERR);}//2. 创建server端的struct sockaddrstruct sockaddr_in server;memset(&server,0,sizeof(server));//初始化方案2server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(server_ip.c_str());server.sin_port = htons(server_port);//3. 客户端测试while(true){// 用户发送消息string messages;cout << "client : " ;cin >> messages;// 发送到socksendto(sock,messages.c_str(),messages.size(),0,(struct sockaddr*)&server,sizeof(server));// 接受返回的信息char buffer[1024];struct sockaddr_in temp;socklen_t len = sizeof(temp);int n = recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);if(n > 0){buffer[n] = 0;cout << buffer << endl;}}return 0;
}

5. errno.hpp

#pragma onceenum
{USAGE_ERR = 1,SOCKET_ERR,BIND_ERR
};

6. makefile

.PHONY:all
all: udp_client udp_serverudp_client:udp_client.ccg++ -o $@ $^ -std=c++11
udp_server:udp_server.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f udp_client udp_server

三、udp服务器(第二版)

1. 添加回调函数

第一版的udp服务器,我们只要求能够收发信息,但我们实际应用中,服务端接受到信息以后,还需要对信息进行后续的处理,而具体的处理方法,我们这里简单设计几个例子。

所以我们应该对udp_server.hpp的设计进行补充和改进,我们对类的设计可以多添加一个表示具体执行方法的成员,由外部传入具体的方法,类内只需要拿到方法后,以回调的方式去处理接受到的信息,并且将处理好的信息发送回给客户端。

———————————————————————————————————————————

知识点一

在c语言中,通常是用typedef的方式去定义一个函数指针类型,而在C++中,例如我想定义一个类型string fun_t(string msg) 这样一个类型的函数指针,我们通常使用以下方式:

#include <functional>using func_t = std::function<std::string(std::string)>;

ps:这里用到的方法细究的话,知识点有点多,可以先简单的认为,这就是定义一个函数指针的方法,实际用处更加广泛,这个本质也不是函数指针。

———————————————————————————————————————————

基于上述在知识点,我们定义函数指针,添加函数指针变量的类成员对象,然后调整下构造,选择让外部传入具体方法,这样就实现了方法处理和网络传输的解耦,然后再对于之前的逻辑进行调整,我们拿到数据后,先将数据交给回调函数,然后将处理好后的信息再发生给客户端

2. 信息处理函数

这里我们简单的写几个功能进行测试即可

2.1 大小写转换

先简单实现一个,将对方发送过来的字符串信息中,关于小写的字母转换成大写返回

———————————————————————————————————————————

知识点一

这里是整理了一下要实现这个函数的一些接口,不算新的知识点

字符检查相关接口

#include<ctype.h>int isalpha(int c); // 检查是否为字母
int islower(int c); // 检查是否为小写字母
int isupper(int c); // 检查是否为大写字母

英文字符大小写转化的相关接口

#include <ctype.h>int toupper(int c); //小写转化成大写
int tolower(int c); //大写转化成小写

———————————————————————————————————————————

代码参考

string transacationString(string msg)
{string res;char tmp;for(auto& c:msg){if(islower(c)){tmp = toupper(c);res.push_back(tmp);}else{res.push_back(c);}}return res;
}

2.2 远程指令控制

这里要做一个让远程的客户端传指令给服务器,服务器处理并将结果返回,我们可以像之前一样,去封装一个命令行解释器,调用创建线程去处理并将结果返回,这里不选择自己造轮子,而是通过已有的接口去直接实现这个命令的处理,并返回相对应的处理结果。

———————————————————————————————————————————

知识点一:命令行执行接口

   FILE *popen(const char *command, const char *type);

作用:创建一个子进程去执行command命令,并且创建管道连接这个子进程,通过type指定去连接到这个指令的标准输出或者标准输入

  • command:要执行的 shell 命令字符串。
  • type:指定管道的方向,可以是 "r"(读)或 "w"(写)。如果是 "r",则创建的管道连接到命令的标准输出,可以从这个管道读取命令的输出。如果是 "w",则连接到命令的标准输入,可以向这个管道写入数据作为命令的输入。
  • 如果成功,返回一个指向FILE类型的指针,可以使用标准 I/O 函数(如freadfwritefgets等)来与管道进行交互。
  • 如果失败,返回NULL,并设置errno来指示错误原因。

   int pclose(FILE *stream);

作用:pclose函数用于关闭由popen函数创建的管道,并等待与该管道关联的进程结束。

  • stream:由popen函数返回的指向管道的FILE指针。

———————————————————————————————————————————

参考代码

// 远程指令
std::string excuteCommand(std::string command)
{//1. 安全检查:避免对方输入一些你不愿意提供的指令,例如rm等等//这部分我们只是简单做测试,就不进行安全检查了//2. 业务处理逻辑FILE* fp = popen(command.c_str(),"r");if(fp == nullptr) return "Invalid instruction";//3. 获取结果char line[1024];std::string res;while(fgets(line,sizeof(line),fp)){res += line;}pclose(fp);return res;
}

四、udp服务器(第三版)

服务端除了这种对信息的处理然后返回,我们还可以简单的做一个群聊功能玩玩。

群聊的要求就是,我们多个客户端向服务器发送消息,服务器首先需要每个都拿到,并且将受到的消息,广播给每一个在线用户,要实现这些,首先要解决的就是,我需要将消息发送到每一个客户端上,我就要有一个存放每一个在线用户信息的一个容器,这里做的稍微简单一点,我们认为只要给我发送了消息,我就将你的客户端信息记录起来,认为你当前处于“在线状态”,然后将你的信息向每一个用户进行发送,此时如果有其他用户也给服务端发送信息怎么办?这就涉及到多线程并发访问的问题,我们利用前面学习到的生产消费模型去处理,多个线程发送消息到循环队列中,而服务器每次往循环队列拿信息,并且广播。而为了测试时观赏性更强一点,我们还可以利用管道文件,将内容输入重定向到管道文件中,再另外开一个窗口,把管道文件的内容打印出来。

参考代码

Linux —— udp实现群聊代码-CSDN博客

总结

本篇重点是延续上一篇,进一步改造了udp服务端,简单的补充和添加了几个功能,并且提供了代码进行参考。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com