TCP套接字编程介绍

本文程序介绍(共5部分)

  1. TCP API 封装
  • Socket() 创建套接字
  • Close() 关闭套接字
  • Bind() 绑定地址信息
  • Listen() 使一个套接字成为监听套接字
  • Connect() 建立连接请求
  • Accept() 接受连接请求
  • Send() 发送请求
  • Recv() 接收响应
  1. TCP 通用服务器 (普通版本,多进程版本,多线程版本)

普通版本:同一时刻只能与一个客户端进行通信,当前客户端断开连接才能与其他客户端建立新的连接
多进程/多线程版本:可以同时和多个客户端进行通信

  1. TCP 通用客户端

  2. TCP 英译汉服务器

封装后的服务器程序可以只更改一个函数就实现不同的功能

  1. TCP 英译汉客户端

TCP API 封装

/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  tcp_socket.hpp
*    Author:    shen
*    Last modified: 2019-07-29 11:11
*    Description: 封装tcp api
*       Socket()    创建套接字
*       Close()     关闭套接字
*       Bind()      绑定地址信息
*       Listen()    使一个套接字成为监听套接字
*       Connect()   建立连接请求
*       Accept()    接受连接请求
*       Send()      发送请求
*       Recv()      接收响应
==============================================================*/
#include <iostream>
#include <string>
#include <stdio.h>
#include <cassert>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>#define CHECK_RET(q) if(!(q)) {return false;}class TcpSocket {public:TcpSocket() : _fd(-1) {}TcpSocket(int fd) :_fd(fd) {}~TcpSocket(){}//绑定地址信息-IPV4协议,字节流传输bool Socket() {_fd = socket(AF_INET, SOCK_STREAM, 0);if (_fd < 0) {perror("socket error~~\n");return false;}return true;}//关闭套接字bool Close() {int ret = close(_fd);if (ret < 0) {perror("close error~~\n");return false;}return true;}//为套接字绑定地址信息,地址为一个通用的结构体sockaddr//结构体包含了协议类型,ip地址,port端口号bool Bind(std::string& ip, uint16_t port) {sockaddr_in addr;addr.sin_family = AF_INET;//inet_addr点分十进制字符串转换为网络ip(本质上是一个32字节数据)addr.sin_addr.s_addr = inet_addr(ip.c_str());//htons主机字节序转换为网络字节序addr.sin_port = htons(port);int ret = bind(_fd, (sockaddr*)&addr, sizeof(addr));if (ret < 0) {perror("bind error~~\n");return false;}return true;}//开始监听,num=5 最多允许5个客户端处于连接等待状态bool Listen(int num = 5) {int ret = listen(_fd, num);if (ret < 0) {perror("listen error~~\n");return false;}return true;}//监听套接字用于接受连接请求,建立连接后会accept返回一个新的套接字//这个套接字就是客户端建立的套接字,是真正用于进行通信的套接字//而监听套接字不用于进行通信//同时可以接收到对端的地址信息bool Accept(TcpSocket& peer, std::string* ip = nullptr, uint16_t* port = nullptr) {sockaddr_in addr;socklen_t len = sizeof(addr);int new_sock = accept(_fd, (sockaddr*)&addr, &len);if (new_sock < 0) {perror("accept error~~\n");return false;}peer._fd = new_sock;if (ip != nullptr) {*ip = inet_ntoa(addr.sin_addr);}if (port != nullptr) {*port = ntohs(addr.sin_port);}return true;}//请求建立连接,客户端使用bool Connect(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 = connect(_fd, (sockaddr*)&addr, sizeof(addr));if (ret < 0) {perror("connect error~~\n");return false;}return true;}//发送消息bool Send(std::string& buf) {int ret = send(_fd, buf.c_str(), buf.size(), 0);if (ret < 0) {perror("send error~~\n");return false;}return true;}//接收消息bool Recv(std::string& buf) {char tmp[1024*4] = {0};int len = recv(_fd, tmp, sizeof(tmp)-1, 0);if (len < 0) {perror("recv error~~\n");return false;}if (len == 0) {return false;}buf.assign(tmp, len);return true;}int GetFd() {return _fd;}private:int _fd;
};

TCP 通用服务器

1. 普通版本
/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  tcp_server.hpp
*    Author:    shen
*    Last modified: 2019-07-29 11:15
*    Description: 通用的服务端程序
==============================================================*/
#include "tcp_socket.hpp"
#include <functional>typedef std::function<void (const std::string& req, std::string& resp)> Handler;class TcpServer {public:TcpServer(std::string& ip, uint16_t port): _ip(ip), _port(port){}~TcpServer() {}bool Start(Handler handler) {//1.创建套接字CHECK_RET(sock.Socket());//2.绑定地址信息CHECK_RET(sock.Bind(_ip, _port));//3.开始监听CHECK_RET(sock.Listen());//4.进入事件循环while (true) {//新的套接字,用于接受客户端的套接字TcpSocket new_sock;std::string ip;uint16_t port;//5.阻塞建立新连接if(!sock.Accept(new_sock, &ip, &port))continue;printf("[ip-%s][port-%d] --> connect~~\n", ip.c_str(), port);//6.对新建立的连接循环读写while (true) {//7.接收请求,失败跳出循环并且关闭新的连接std::string req;bool ret = new_sock.Recv(req);if (!ret) {printf("[ip-%s][port-%d] --> disconnect~~\n", ip.c_str(), port);break;}std::cout << "请求:" << req << std::endl;//8.计算响应std::string resp;handler(req, resp);//9.发送响应new_sock.Send(resp);}new_sock.Close();}return true;}private:TcpSocket sock;std::string _ip;uint16_t _port;
};
2. 多进程版本
/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  tcp_pross_server.hpp
*    Author:    shen
*    Last modified: 2019-08-01 09:42
*    Description: 通用的服务端程序(多进程)
==============================================================*/
#include "tcp_socket.hpp"
#include <functional>
#include <signal.h>typedef std::function<void (const std::string& req, std::string& resp)> Handler;class TcpServer {public:TcpServer(std::string& ip, uint16_t port): _ip(ip), _port(port){}~TcpServer() {}bool Start(Handler handler) {//避免僵尸子进程,对子进程退出时发给父进程的信号忽略处理signal(SIGCHLD, SIG_IGN);//1.创建套接字CHECK_RET(sock.Socket());//2.绑定地址信息CHECK_RET(sock.Bind(_ip, _port));//3.开始监听CHECK_RET(sock.Listen());//4.进入事件循环while (true) {//新的套接字,用于接受客户端的套接字TcpSocket new_sock;std::string ip;uint16_t port;//5.阻塞建立新连接if(!sock.Accept(new_sock, &ip, &port))continue;printf("[ip-%s][port-%d] --> connect~~\n", ip.c_str(), port);//多进程版本ProssCommunication(new_sock, handler);}return true;}private:void ProssCommunication(TcpSocket& new_sock, Handler handler) {//1.创建子进程,用子进程和客户端进行通信//2.父进程直接退出该函数,退出前要先关闭通信套接字//3.子进程关闭监听套接字//4.子进程结束时也需要将通信套接字关闭pid_t pid = fork();if (pid > 0) {//父进程new_sock.Close();return;}if (pid == 0) {sock.Close();//先关闭监听套接字while (true) {//1.接受请求//2.计算响应//3.发送响应std::string req;int ret = new_sock.Recv(req);if (ret == 0) {printf("pross disconnect~~\n");break;}printf("[pross]请求: %s\n", req.c_str());std::string resp;handler(req, resp); new_sock.Send(resp);}//通信结束new_sock.Close();exit(0);}}private:TcpSocket sock;std::string _ip;uint16_t _port;
};
3. 多线程版本
/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  tcp_thread_server.hpp
*    Author:    shen
*    Last modified: 2019-08-01 10:13
*    Description: 通用的服务端程序(多线程版本)
==============================================================*/
#include "tcp_socket.hpp"
#include <functional>
#include <pthread.h>typedef std::function<void (const std::string& req, std::string& resp)> Handler;struct ThreadArg {TcpSocket client_sock;std::string ip;uint16_t port;Handler handler;
};class TcpServer {public:TcpServer(std::string& ip, uint16_t port): _ip(ip), _port(port){}~TcpServer() {}bool Start(Handler handler) {//1.创建套接字CHECK_RET(sock.Socket());//2.绑定地址信息CHECK_RET(sock.Bind(_ip, _port));//3.开始监听CHECK_RET(sock.Listen());//4.进入事件循环while (true) {ThreadArg* arg = new ThreadArg;arg->handler = handler;//5.阻塞建立新连接if(!sock.Accept(arg->client_sock, &arg->ip, &arg->port))continue;printf("[ip-%s][port-%d] --> connect~~\n", arg->ip.c_str(), arg->port);pthread_t tid;pthread_create(&tid, NULL, ThreadEntry, (void*)arg);pthread_detach(tid);}sock.Close();return true;}static void* ThreadEntry(void* arg) {//1.创建线程,线程入口函数参数用一个结构体存储//2.线程分离//3.线程入口函数用 static,线程入口函数没有this指针传参//4.最后关闭描述符,释放堆空间ThreadArg* p = (ThreadArg*)arg;while (true) {std::string req;int ret = p->client_sock.Recv(req);if (ret == 0) {printf("thread disconnect~~\n");break;}printf("thread 请求: %s\n", req.c_str());std::string resp;p->handler(req, resp);p->client_sock.Send(resp); }//关闭描述符,并且释放内存p->client_sock.Close();delete p;return NULL;}private:TcpSocket sock;std::string _ip;uint16_t _port;
};

TCP 通用客户端

/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  tcp_client.hpp
*    Author:    shen
*    Last modified: 2019-07-29 12:09
*    Description: 通用客户端程序
==============================================================*/
#include "tcp_socket.hpp"class TcpClient {public:TcpClient(std::string& ip, uint16_t port) : _ip(ip), _port(port) {assert(sock.Socket());}~TcpClient() {assert(sock.Close());}bool Connect() {return sock.Connect(_ip, _port);} bool Recv(std::string& req) {return sock.Recv(req);}bool Send(std::string& resp) {return sock.Send(resp);}private:TcpSocket sock;std::string _ip;uint16_t _port;
};

TCP 英译汉服务器

/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  dict_server.cpp
*    Author:    shen
*    Last modified: 2019-07-29 11:53
*    Description:
==============================================================*/
#include "tcp_server.hpp"
#include <unordered_map>void Dict(const std::string& req, std::string& resp) {std::unordered_map<std::string, std::string> dic;dic.insert(std::make_pair("hello", "你好~~"));dic.insert(std::make_pair("world", "世界~~"));dic.insert(std::make_pair("shen", "珅~~"));if (dic.find(req) != dic.end()) {auto it = dic.find(req);resp = it->second;} else {resp = "未找到~~";}
}// ./dict_server 127.0.0.1 9000
int main(int argc, char* argv[]) {if (argc != 3) {std::cout << "./dict_server 127.0.0.1 9000" << std::endl;return -1;}std::string ip = argv[1];uint16_t port = atoi(argv[2]);TcpServer server(ip, port);server.Start(Dict);return 0;
}

TCP 英译汉客户端

/*==============================================================
*    Copyright . All rights reserved.
*    Filename:  dict_client.cpp
*    Author:    shen
*    Last modified: 2019-07-29 12:23
*    Description:
==============================================================*/
#include "tcp_client.hpp"// ./dict_client 127.0.0.1 9000
int main(int argc, char* argv[]) {if (argc != 3) {std::cout << "./dict_client 127.0.0.1 9000" << std::endl;return -1;}std::string ip = argv[1];uint16_t port = atoi(argv[2]);TcpClient client(ip, port);client.Connect();while (true) {std::string req;std::cout << "请求:";std::cin >> req;client.Send(req);std::string resp;client.Recv(resp);std::cout << "响应:" << resp << std::endl;}return 0;
}

TCP-实现英译汉服务器客户端(多进程/多线程)相关推荐

  1. 计算机专业外语英译汉,信科计算机专业英语英译汉

    计算机专业英语句子翻译,参考 信息科学与工程学院,计算机专业英语英译汉作业,仅供参考 Translate this sentences into Chinese: 1. In reality, com ...

  2. 金融财务英译汉常用词怎样翻译

    我们知道,金融财务的本质是价值流通,金融翻译产品种类多种多样,所涉及翻译文件与银行.证券.保险﹑基金.信托.融资,以及与国际收支.汇兑.结算.信用.投资等领域相关.金融财务翻译的一个难点就是常用名词, ...

  3. python评分卡4_logistics原理与解法_sklearn英译汉

    本系列分以下章节: python评分卡1_woe与IV值 python评分卡2_woe与IV分箱方法 python评分卡3_woe与IV分箱实现 python评分卡4_logistics原理与解法_s ...

  4. 《keep studying》————《持续学习》英译汉【istrangeboy精品英文励志短文系列】

    <keep studying>----<持续学习>英译汉dd by istrangeboy it's very simple.the attitude you have whe ...

  5. 《succes can be a lonely road》 【istrangeboy精品英文励志短文系列】之最美英文励志诗《成功是一条孤独之路》英译汉

    <succes can be a lonely road> --<成功是一条孤独之路>英译汉 by istrangeboy success can be a lonely ro ...

  6. 英译汉在线翻译器如何实现英文语音翻译中文

    英译汉在线翻译器如何实现英文语音翻译中文?对于出国游玩的朋友来说,首先要解决的就是语言沟通问题,否则即使去了国外,面对语言障碍,恐怕也没有游玩的心情.今天小编将要为大家分享一个英文翻译中文的好方法,帮 ...

  7. java设计单词英译汉小助手_java课程设计——英汉电子词典编程

    Java课程设计--英汉电子词典 一.需求分析 二十世纪后半叶,以电子计算机为代表的现代科学获得了突飞猛进的发展并迅速和人们的日常生活结合在一起.计算机技术的发展和进步也使电子语言词典的诞生成为可能. ...

  8. 新视野大学英语第三版第三册全书的Word In Use翻译和部分单元的英译汉翻译

    转到博客浏览效果可能不佳(比如序号无法正常显示,可以下载文档) 链接:https://www.lanzous.com/b531026/ 密码:2qfl Word In Use Unit1 1.Most ...

  9. 英译汉需要注意的几点

    来自网站: http://www.360doc.com/content/14/0528/07/14153037_381611194.shtml 动宾连接原则 在英译汉时,有许多翻译错误来源于动宾短语的 ...

最新文章

  1. 程序员的自我修养--链接、装载与库笔记:Linux共享库的组织
  2. Jad一个好东西(转载)
  3. 基于MATLAB的LS-SVM实现方法以及SVM的一些知识点
  4. linux下面的浏览器不停自动打开新网页
  5. Eclipse 里一个 SAP Hybris Commerce 的开发插件
  6. Fiber 数据结构是怎样的?
  7. [转]CG编程概念 ,及CG编译器与VC6.0集成方法
  8. Android 下拉刷新库,这一个就够了!
  9. python连接SQLServer数据库创建数据表同时为每个字段加上对应的中文注释信息
  10. 微信UnionID作用
  11. 相爱相杀:移动联通IT支撑回忆录(九)
  12. AI明星上市受阻,是继续融资还是割肉?
  13. 图像处理学习笔记2.0
  14. (一)1. 数据流图(DFD)概念及画法
  15. el-rate的使用
  16. Cleartext HTTP traffic to xxx not permitted解决
  17. JavaWeb 第一章 HTMLCSS
  18. Lucene.Net 实现搜索功能
  19. 密码学之数字签名是什么
  20. 中职计算机专业英语课程改革初探,中职计算机专业英语教学初探

热门文章

  1. ims sip不发起注册问题实操
  2. 初代 iPhone:那道不清说不尽的故事
  3. VS调试技巧:让断点在for循环中i为某个值的时候停下来
  4. mysql性能优化 洪斌_技术分享 | InnoDB Cluster 如何高效加载数据
  5. python socket实现实时通信
  6. 浪潮信息成为龙蜥理事单位,共建开放计算生态和行业方案
  7. 日记 [2007年08月29日]
  8. 高德AR实景导航,出差旅行好帮手,轻轻松松找对路
  9. SharePoint REST API - REST请求导航的数据结构
  10. 详解设计模式:桥接模式