网络套接字补充——TCP网络编程
六、TCP网络编程
6.1IP地址字符串和整数之间的转换接口
//字符串转整数接口
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
int inet_pton(int af, const char *strptr, void *addrptr);//注意dst指的是in_addr *的地址
in_addr_t inet_addr(const char *cp);//将字符串转32位并且是网络序列的;
//整数转字符串
char *inet_ntoa(struct in_addr in);//将整数转为字符串并且将网络字节序转为主机字节序
const char *inet_ntop(int af, const void *addrptr,char *strptr, socklen_t size);
需要注意的是inet_ntoa函数这个函数返回的是一个静态变量地址,使用时有覆盖问题和线程安全问题;最好是使用inet_ntop;
6.2补充知识
1.将网络套接字进行封装
构造函数之中最好少做一些有风险的事情,这样可以保证最起码对象是没有问题的;其他如打开文件之类的操作就交给其他函数去完成;
2.获取新连接会产生多个文件描述符
服务器本地的文件描述符用来进行监听连接,获取新连接,真正进行IO通信的文件描述符是后生成的;这样既提高了服务器的并发度;
3.telnet的使用
默认使用的就是TCP;
使用ctrl+]进入,回车后进行输入(会自动在输入的文本后面加\r\n)会回显数据,q退出;
4.TCP连接中的异常问题
当客户端直接退出时,服务端就会读到0,此时需要关闭为客户端打开的文件描述符;
5.网络抖动断开连接,客户端自动发起连接请求设计
6.tcp服务器重连
服务器断开后不能直接连接,一般要等待120s左右;
6.3使用接口
6.3.1创建套接字
和udp使用是一样的;
6.3.2绑定套接字
和udp使用是一样的;
6.3.3设置监听
由于TCP是面向连接的,所以在通信前要建立连接,将套接字设置为监听状态;
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//第二个参数表示的是全连接的队列的长度,一般不能设置的太大;
6.3.4获取新连接
此处包括以上接口都是阻塞的;
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//返回值,成功返回一个文件描述符,失败返回-1,错误码被设置;
获取新连接成功后要根据客户端的套接字信息提供服务;
6.3.5客户端发起连接请求
客户端需要绑定但是不需要显式进行绑定,系统会在客户端发起连接请求的时候自动绑定;
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
6.4查看网络状态
netstat -nltp
#n显示成数字,l表示listen,表示tcp
6.5单进程版echo服务器
缺陷是同时最多只能有一个客户端进行访问;UDP所有的客户端用的是一个sockfd,一个文件,可以同时读写,而TCP每个客户端对应一个sockfd,一个文件;单进程下对一个文件读写时,服务器因为处理消息是循环处理,必须读完退出循环服务,才能继续获取新连接,此时另一个客户端已经想打开的sockfd文件写入很多数据,当服务端接收连接请求时,会将发送过来的一大批数据处理后返回,这样就无法实现正常的服务器;
char buff[4096];
while (true)
{// 数据读取ssize_t n = read(sockfd, buff, sizeof(buff) - 1);if (n > 0){buff[n] = '\0';std::cout << "client say@ " << buff << std::endl;// 数据回显std::string echo_string;echo_string += "tcpserver say#";echo_string += buff;write(sockfd, echo_string.c_str(), echo_string.size());}else if (n == 0){lg(Info, "%s:%d quit..., server close sockfd: %d", clientip.c_str(), clientport, sockfd);break;}else{lg(Warning, "read error, sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip.c_str(), clientport);break;}
}
6.6多进程版echo服务器
1.子进程可以看见listenfd_,所以要关闭无关的文件描述符;2.父进程不关心sockfd,要去接收新的连接,如果不关闭就会导致之后的很多文件描述符没有关闭,不断从新的下标打开文件描述符,而不是重新分配;
2.子进程中继续fork(),然后子进程退出,被父进程阻塞等待回收,父进程继续获取新的连接,孙子进程被操作系统领养,执行服务部分;也可以使用信号异步等待的方式实现;
3.也可以在循环执行获取连接和执行任务之前创建子进程,但是会存在数据不一致问题需要用信号量;
4.多进程创建的成本过高,所以应该选择多线程;
//方式1
pid_t id = fork();
if (id < 0)
{std::cerr << "fork error" << std::endl;
}
else if (id == 0)
{close(listensockfd_);if (fork() > 0){exit(0);}// 此处执行代码的是孙子进程,会被做系统领养service(sockfd, clientip, clientport);close(sockfd);exit(0);
}
close(sockfd);
pid_t rid = waitpid(id, nullptr, 0);
(void)rid;
//方式2
signal(SIGCHLD, SIG_IGN);
pid_t id = fork();
if (id == 0)
{close(listensockfd_);service(sockfd, clientip, clientport);close(sockfd);exit(0);
}
close(sockfd);
6.7多线程版本的echo服务器
1.因为线程中大部分资源都是共享的所以不可以关闭文件描述符,否则会出错;
2.线程没有退出时会有峰值的,服务器此时压力很大,所以长服务是不合理的;
3.创建线程也是有成本的,即系统调用的成本,所以应该用线程池;
struct threaddata
{threaddata(const int sockfd, const std::string &clientip, const uint16_t &clientport, tcpserver *t) : sockfd_(sockfd), clientport_(clientport),clientip_(clientip), t_(t){}int sockfd_;uint16_t clientport_;std::string clientip_;tcpserver *t_;
};pthread_t tid;
threaddata *td = new threaddata(sockfd, clientip, clientport, this);
pthread_create(&tid, nullptr, routine, (void *)td);static void *routine(void *args)
{threaddata *td = static_cast<threaddata *>(args);pthread_detach(pthread_self());td->t_->service(td->sockfd_, td->clientip_, td->clientport_);delete td;return nullptr;
}
6.8线程池版本的echo服务器
1.线程池里不可以执行长时间的服务;2.服务器关闭了客户端套接字,客户端继续写入,会触发服务器异常,返回一个RST消息,然后客户端操作系统发送SIGPIPE信号杀死客户端进程;
class Task
{public:Task(const int &sockfd, const std::string &clientip, const uint16_t &clientport): sockfd_(sockfd), clientport_(clientport), clientip_(clientip) {}void run(){char buff[4096];// 数据读取ssize_t n = read(sockfd_, buff, sizeof(buff) - 1);if (n > 0){buff[n] = '\0';std::cout << "client say@ " << buff << std::endl;// 数据回显std::string echo_string;echo_string += "tcpserver say#";echo_string += buff;write(sockfd_, echo_string.c_str(), echo_string.size());}else if (n == 0){lg(Info, "%s:%d quit..., server close sockfd: %d", clientip_.c_str(), clientport_, sockfd_);}else{lg(Warning, "read error, sockfd: %d, clientip: %s, clientport: %d", sockfd_, clientip_.c_str(), clientport_);}close(sockfd_);}void operator()(){run();}~Task(){}private:int sockfd_;uint16_t clientport_;std::string clientip_;
};Task t(sockfd, clientip, clientport);
ThreadPool<Task>::GetInstance()->Push(t);#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include "Task.hpp"
#include <unistd.h>struct ThreadInfo
{pthread_t tid;std::string name;
};static const int defaultnum = 5;template <class T>class ThreadPool{private:void Lock(){pthread_mutex_lock(&_mutex);}void UnLock(){pthread_mutex_unlock(&_mutex);}void Wakeup(){pthread_cond_signal(&_cond);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}bool IsQueueEmpty(){return _tasks.empty();}std::string GetThreadName(pthread_t tid){for (const auto e : _threads){if (e.tid == tid){return e.name;}}return "None";}public:T Pop(){T t = _tasks.front();_tasks.pop();return t;}void Push(const T &t){Lock();_tasks.push(t);Wakeup();UnLock();}static void *HandlerTask(void *args) // 类内函数默认都有一个this指针,静态成员函数无法直接看到成员属性{ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);std::string name = tp->GetThreadName(pthread_self());while (true){tp->Lock();while (tp->IsQueueEmpty()){tp->ThreadSleep();}Task t = tp->Pop();tp->UnLock();t();}}void Start() // 创建线程{int num = _threads.size();for (int i = 0; i < num; i++){_threads[i].name = "thread-" + std::to_string(i + 1);pthread_create(&(_threads[i].tid), nullptr, HandlerTask, this);}}static ThreadPool<T> *GetInstance(){pthread_mutex_lock(&_smutex);if (_tp == nullptr){std::cout << "log : singleton create done first!" << std::endl;_tp = new ThreadPool<T>();}pthread_mutex_unlock(&_smutex);return _tp;}private:ThreadPool(int num = defaultnum) : _threads(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}ThreadPool(const ThreadPool<T> &tp) = delete;const ThreadPool<T> &operator=(const ThreadPool<T> tp) = delete;~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}std::vector<ThreadInfo> _threads;std::queue<T> _tasks;pthread_mutex_t _mutex;pthread_cond_t _cond;static ThreadPool<T> *_tp;static pthread_mutex_t _smutex;};
template <class T>ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <class T>pthread_mutex_t ThreadPool<T>::_smutex = PTHREAD_MUTEX_INITIALIZER;
6.9线程池版翻译服务器
打开KV式的字符串文件,来比较进行翻译;
#include <iostream>
#include <string>
#include <unordered_map>
#include <fstream>
#include <cstring>
#include "log.hpp"extern Log lg;const std::string filename = "./dict.txt";// 打开字典并且自动将初始化dict
class init
{public:bool split(const std::string &line, std::string &part1, std::string &part2){auto pos = line.find(sep);if (pos == std::string::npos){return false;}part1 = line.substr(0, pos);part2 = line.substr(pos + sep.size());return true;}init(){// 1.打开文件std::ifstream in(filename); // 默认打开文件if (!in.is_open()){lg(Fatal, "open %s file error, errno: %d, strerror: %s", filename.c_str(), errno, strerror(errno));exit(4);}std::string line;// 2.对文件进行按行读取while (std::getline(in, line)){std::string part1, part2;split(line, part1, part2);dict_[part1] = part2;}// 3.关闭文件in.close();}std::string translation(const std::string &key){auto it = dict_.find(key);if (it != dict_.end()){return dict_[key];}else{return "unknown";}}private:std::unordered_map<std::string, std::string> dict_;static const std::string sep;
};
const std::string init::sep = ": ";
// 处理任务
buff[n] = '\0'; // 当作字符串使用
std::string echo_string;
echo_string += it.translation(buff);
write(sockfd_, echo_string.c_str(), echo_string.size());
相关文章:
网络套接字补充——TCP网络编程
六、TCP网络编程 6.1IP地址字符串和整数之间的转换接口 //字符串转整数接口 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int inet_aton(const char *cp, struct in_addr *inp); int inet_pton(int af, const char *strptr, …...
Nginx-记
Nginx是一个高性能的web服务器和反向代理服务器,用于HTTP、HTTPS、SMTP、POP3和IMAP协议。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。 (1)更快 这表现在两个方面:一方面,在正常情况下&…...
JS面试题:call,apply,bind区别
1. 共同点 三者共同点都是改变函数内部this指向的方法 2. call用法 ini 复制代码 var a 2; var b 2; function func() { console.log(this.a, this.b) } let obj { a: 1, b: 1 } func.call(obj) func.call() 输出结果: 复制代码 1 1 2 2 解析࿱…...
Charles抓包配置代理手机连接
Charles下载地址: Charles_100519.zip官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘123云盘为您提供Charles_100519.zip最新版正式版官方版绿色版下载,Charles_100519.zip安卓版手机版apk免费下载安装到手机,支持电脑端一键快捷安装https://www.123pan.com…...
NA555、NE555、SA555和SE555系列精密定时器
这份文件是关于德州仪器(Texas Instruments)生产的NA555、NE555、SA555和SE555系列精密定时器(Precision Timers)的数据手册。以下是该文件的核心内容概述: 产品特性: 德州仪器的NA555、NE555、SA555和SE55…...
黑马鸿蒙笔记2
1.图片设置: 1 加载网络图片,申请权限。 申请权限:entry - src - resources - module.json5 2 加载本地图片 ,两种加载方式 API 鼠标悬停在Image, 点击show in API Reference interpolation:看起来更加清晰 resou…...
微信小程序uniapp+vue3+ts+pinia的环境搭建
一.创建uniapp项目 通过vue-cli创建 npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project二.安装依赖: 1.pnpm i 2.运行项目: 将package.json的 "dev:mp-weixin": "uni -p mp-weixin",改为 "serve": "u…...
MongoDB聚合运算符:$let
文章目录 MongoDB聚合运算符:$let语法使用举例 MongoDB聚合运算符:$let $let聚合运算符绑定用于表示计算的变量,并返回表达式的结果。 语法 {$let:{vars: { <var1>: <expression>, ... },in: <expression>} }vars 用于在…...
HarmonyOS像素转换-如何使用像素单位设置组件的尺寸。
1 卡片介绍 基于像素单位,展示了像素单位的基本知识与像素转换API的使用。 2 标题 像素转换(ArkTS) 3 介绍 本篇Codelab介绍像素单位的基本知识与像素单位转换API的使用。通过像素转换案例,向开发者讲解了如何使用像素单位设…...
【前端面试3+1】05v-if和v-show的区别、v-if和v-for能同时使用吗、Vuex是什么?【合并两个有序链表】
一、v-if和v-show的区别 v-if 和 v-show 是 Vue.js 中用来控制元素显示与隐藏的指令。 1.v-if: v-if 是根据表达式的真假值来决定是否渲染元素。当表达式为真时,元素会被渲染到 DOM 中;当表达式为假时,元素不会被渲染到 DOM 中。每…...
Unity WebRequest 变得简单
作者简介: 高科,先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢你的关注…...
vue 窗口内容滚动到底部
onMounted(() > {scrollToBottom() }) // 滚动到底部方法 const scrollToBottom () > {// 获取聊天窗口容器let chatRoom: any document.querySelector(".chat-content");// 滚动到容器底部chatRoom.scrollTop chatRoom.scrollHeight; } 效果 聊天窗口代码…...
代码随想录算法训练营Day38|LC509 斐波那契数列LC70 爬楼梯LC746 使用最小花费爬楼梯
一句话总结:难的还在后头呢。 原题链接:509 斐波那契数列 甚至用不上数组,用两个变量滚动交替即可完成。 class Solution {public int fib(int n) {if (n < 2) return n;int pre 0, cur 1;int ans 0;for (int i 2; i < n; i) {an…...
Qt5.14.2 大神的拖放艺术,优雅而强大的交互体验
作为图形界面软件,良好的用户交互体验是制胜的关键。而在Qt大神们的绝世编程之道中,拖放操作无疑占据着非常重要的一席之地。它不仅操作简单直观,而且可以完成大量看似复杂的任务,是提升用户体验质量的利器。今天,就让…...
python3将exe 转支持库错误 AssertionError: None does not smell like code
exe -> pyc包(*.exe_extracted) 安装反编译工具 exe反编译工具:pyinstxtractor.py下载:https://sourceforge.net/projects/pyinstallerextractor/ python pyinstxtractor.py hello.exe包反编译 懒的写!!! 这有详…...
[EFI]Dell Inspiron 15 5567 电脑 Hackintosh 黑苹果efi引导文件
硬件型号驱动情况主板 Dell Inspiron 15R 5567 处理器Intel Core i7-7500U 2.50 GHz Processor (4M Cache, up to 3.50 GHz)已驱动内存8GB, 2400MHz, DDR4, up to 16GB已驱动硬盘东芝 NVMe 512G已驱动显卡Intel HD Graphics 620已驱动声卡ALC3246 Analog (ALC256)已驱动网卡无无…...
大学 Python 程序设计实验报告:判断密码是否符合要求
目录: 利用 string 模块判断使用正则表达式判断 密码强度判断,输入一个密码,判断密码是否符合要求。 要求密码长度8-12位,密码中必须包含大写字母、小写字母和数字,不能含有其他符号。 如果符合要求输出"密码符合…...
基于SpringBoot的农产品直卖平台
采用技术 基于SpringBoot的农产品直卖平台的设计与实现~ 开发语言:Java 数据库:MySQL 技术:SpringBootMyBatis 工具:IDEA/Ecilpse、Navicat、Maven 页面展示效果 用户功能 农产品信息 确认下单 农产品订单 购物车 商家功…...
DevSecOps平台架构系列-微软云Azure DevSecOps平台架构
目录 一、概述 二、Azure DevOps和黄金管道 2.1 概述 2.2 Azure DevOps架构说明 2.2.1 架构及管道流程图 2.2.2 架构内容 2.2.2.1 Azure Boards 2.2.2.2 Azure Repos 2.2.2.3 Azure Test Plans 2.2.2.4 Azure Pipelines 2.2.2.5 Azure Application Insights 2.2.2.6…...
操作系统:管程与进程通信机制解析
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
