SOCKET:
//封装的形式实现 #include <stdio.h> #include <cstdio> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <cstringt> #include <sys/socket.h> //socket相关 #include <netinet/in.h> #include <arpa/inet.h>//htons() #include <cstringt> //sendto() class TcpSocket { public: TcpSocket() :fd_(-1){ } bool Socket() { //和 UDP 不一样是第二个函数 SOCK_STREAM 意思面向字节流 fd_ =socket(AF_INET,SOCK_STREAM,0); if (fd_ < 0) { perror("socket"); return false; } 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 Listen() { //int listen(int socket, int backlog); //int socket:文件描述符 //int backlog:队列的长度 int ret=int listen(fd_, 10); if (ret<0) { perror("listen"); return false; } return true; } //给服务器 bool Accept(TcpSocket* peer, std::string& ip = NULL, uint16_t port=NULL) { //int accept(int socket, struct sockaddr* address, socklen_t* address_len); //struct sockaddr* address:对端的 ip 地址,端口号。 //从连接队列中去一个连接到用户代码中,如果队列中没有连接,阻塞(默认行为) sockaddr_in peer_addr; socklen_t len = sizeof(peer_addr); //设置初始值 //返回值也是一个socket,类似内场销售 int client_socket = accept(fd_, (sockaddr*)&peer_addr, &len); if (client_socket < 0) { perror("accept"); return false; } peer->fd_ = client_socket; if (ip !=NULL) { *ip = inet_ntoa(peer_addr.sin_addr); } if (port != NULL) { *port = ntohs(peer_addr.sin_port); } return true; } //给客户端+服务器 int Recv(std::string& msg) { msg->clear(); char buf[1024 * 10] = { 0 }; ssize_t n = recv(fd_, buf, sizeof(buf)-1, 0); //返回值成功:返回读到的字节数;失败,返回-1,如果是对端关闭了socket,但会结果是 0 。 if (n<0) { perror("recv"); return -1; } else if (n==0) { return 0; } msg->assign(buf); //读到的数据赋值到msg中 return 1; } //给客户端+服务器 bool Send(const std::string& msg) { ssize_t n = send(fd_, msg.c_str(), msg.size(), 0); if (n < 0) { perror("send"); return false; } return true; } //给客户端 bool Connect(const std::string& ip, uint16_t port) { sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip.c_str()); int ret = connect(fd_, (sockaddr*)&addr, sizeof(addr)); if (ret < 0) { perror("connect"); return false; } return true; } bool Close() { if (fd_ != 1) { close(fd_); } return true; } private: int fd_; };
TCP服务端封装:(多进程)
#include "TCPSOCKET.hpp" #include <functional> #include <cassert> typedef std::function<void(const std::string&, std::string*)> Handler; #define CHECK_RET(exp)if(!(exp)) {\ return false; \ } class TcpProcessServer { public: TcpProcessServer() { } ~TcpProcessServer() { listen_sock_.Close(); } bool Start(const std::string& ip, uint16_t port,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 (true) { //5.调用Accept TcpSocket client_sock; std::string peer_ip; std::string peer_port; bool ret = listen_sock_.Accept(&listen_sock_,&peer_ip, &peer_port); if (!ret) { continue; } printf("[%s:%d] 客户端建立连接!\n", peer_ip, peer_port); //6.创建子进程,让子进程回应客户端请求,父进程继续调用Accept ProcessConnect(client_sock,peer_ip,peer_port,handler); } } private: TcpSocket listen_sock_; void ProcessConnect(TcpSocket& clicent_sock, const std::string& ip, uint16_t port, Handler handler) { //1.创建子进程 pid_t ret = fork(); //2.父进程结束函数 if (ret > 0) { //父进程 //父进程也需要关闭这个slcket //否则文件描述符泄露 clicent_sock.Close(); return; } //3.子进程循环的和客户端交互:三件事 // a.读取客户端请求 while (true) { std::string req; int r = clicent_sock.Recv(&req); if (r < 0) { continue; } if (r==0) { printf("[%s:%d] 客户端断开连接\n", ip.c_str(), port); break; } } // b.计算响应 std::string resp; handler(req, resp); // c.响应反馈给客户端 clicent_sock.Send(resp); } //子进程的收尾工作 //1.关闭socket clicent_sock.Close(); //2.结束进程 exit(0); };
TCP服务端封装:(多线程)
#include "TCPSOCKET.hpp" #include <functional> #include <cassert> #include<singal.h> #include <pthread.h> typedef std::function<void(const std::string&, std::string*)> Handler; #define CHECK_RET(exp)if(!(exp)) {\ return false; \ } class TcpProcessServer { public: TcpProcessServer() { } ~TcpProcessServer() { listen_sock_.Close(); } bool Start(const std::string& ip, uint16_t port, 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 (true) { //5.调用Accept TcpSocket client_sock; std::string peer_ip; std::string peer_port; bool ret = listen_sock_.Accept(&listen_sock_, &peer_ip, &peer_port); if (!ret) { continue; } printf("[%s:%d] 客户端建立连接!\n", peer_ip, peer_port); //6.创建线程,让新线程回应客户端请求,主线程继续调用Accept ProcessConnect(client_sock, peer_ip, peer_port, handler); } } private: TcpSocket listen_sock_; struct ThreadEntryArg { TcpSocket& clicent_sock, std::string ip, uint16_t port, Handler handler }; void ProcessConnect(TcpSocket& clicent_sock, const std::string& ip, uint16_t port, Handler handler) { //1.创建线程 pthread_t tid; ThreadEntryArg* arg = new ThreadEntryArg; arg.clicent_sock = clicent_sock; ard.ip = ip; arg.port = port; arg.handler = handler; pthread_creat(tid, NULL, ThreadEntry, arg); //2.主线程返回 pthread_detach(tid); //3.新线程循环的和客户端交互:三件事 } TcpSocket& clicent_sock, const std::string& ip, uint16_t port, Handler handler static void* ThreadEntry(void* arg) { ThreadEntryArg* argument = (ThreadEntryArg*)arg; TcpSocket clicent_sock = argument->clicent_sock; std::string& ip = argument->ip; uint16_t port = argument->port; Handler handler = argument->handler while (true) { // a.读取客户端请求 std::string req; int ret = clicent_sock.Recv(&req); if (ret < 0) { continue; } if (ret == 0) { printf("[%s:%d] 客户端断开连接\n", ip.c_str(), port); clicent_sock.Close(); break; } // b.计算响应 printf("[%s:%d] 客户端请求响应\n", ip.c_str(), req.c_str()); std::string resp; handler(req, resp); // c.响应反馈给客户端 clicent_sock.Send(resp); } delete argument; } };
中英文翻译服务端:
//#include "封装TCP服务端.hpp" #include <unordered_map> //#include "封装多进程TCP服务端.hpp" #include "封装多线程TCP服务端.hpp" int main() { TcpProcessServer server; std::unordered_map<std::string, std::string> dict; dict.insert(std::make_pair("heallo", "你好")); dict.insert(std::make_pair("world", "世界")); dict.insert(std::make_pair("bit", "比特")); server.Start("0.0.0.0", 9090, [](const std::string& req, std::string* resp) { auto it = dict.find(req); if (it == dict.end()) { *resp = "未找到"; } else { *resp = it->second; } }); system("pause"); return 0; }
TCP封装客户端:
#include "TCPSOCKET.hpp" class TcpClient { public: TcpClient() { sock_.Socket(); } ~TcpClient() { sock_.Close(); } bool Connect(const std::string& ip, uint16_t port) { return sock_.Connect(ip,port); } int Recv(std::string* msg) { return sock_.Recv(msg); } bool Send(const std::string& msg) { return sock_.Send(msg); } private: TcpSocket sock_; };
中英文翻译客户端:
#include "封装的TCP客户端.hpp" int main(int argc,char* argv[]) { if (argc !=2) { printf("Usage ./dict_client [ip]\n"); return 1; } TcpClient clicent; bool ret = clicent.Connect(argv[1], 9090); if (!ret) { return 1; } while (true) { //从标准输入数据 printf("请输入要查询的单词:\n"); fflush(stdout); char req[1024] = { 0 }; scanf("%s", req); //把读到的数据给服务器 clicent.Send(req); std::string resp; //读取服务器响应的结果 clicent.Recv(&resp); //把响应的结果打印到标准输出上 printf("resp: %s\n", resp.c_str()); } system("pause"); return 0; }
Linux网络编程(5)——多进程、多线程实现TCP简易中英文翻译
最新推荐文章于 2022-02-10 16:29:52 发布