网络套接字补充——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…...
inno setup 卸载程序 删除整个安装目录
业务场景:有次客户反馈说,卸载应用程序没有卸载干净,安装目录下残留很多文件,特别是一些配置文件和数据库文件,涉及到一些数据安全机密。卸载程序应该把安装目录都要清除。操作如下: 卸载应用程序…...
【Vue3源码学习】— CH2.5 reactiveEffect.ts:Vue 3响应式系统的核心
reactiveEffect.ts:Vue 3响应式系统的核心 1. 什么是 reactiveEffect?2. 核心机制2.1 依赖收集(Track)2.2 触发更新(Trigger)2.3 效果范围(effectScope) 3. 源码解析 —— track3.1 …...
K8S的mountPath和subPath
1 mountPath mountPath是容器内部文件系统的挂载点,它定义了容器内部将外部存储卷(如 PersistentVolume、ConfigMap、Secret 等)挂载到哪个路径下。通过 mountPath,容器可以访问这些挂载的数据或配置。 2 subPath subPath 是 m…...
notepad++里安装32位和64位的16进制编辑器Hex-Editor
这个16进制编辑器确实是个好东西,平时工作种会经常用到, 这是hex-editor的官网。这个里边只能下载32位的(64位的看最下边),选一个合适的版本,我当时选的是最新的版本 https://sourceforge.net/projects/npp-plugins/files/Hex%20E…...
Python类的基本结构
当我们在Python中定义类时,我们实际上是在创建一种新的数据类型。类允许我们定义对象的属性和方法,从而构建更复杂的程序。让我们深入探讨一下关于类的一些重要概念。 定义类:基本结构 一个类的基本结构包括以下部分: 类名&…...
利用HIVE的窗口函数进行SQL查询中出现的问题记录
student_info部分数据 score_info部分数据 course_info 1、问题复现 --完整SQL selectsti.stu_id,sti.stu_name,concat_ws(",",collect_set(ci.course_name)) over(partition by sti.stu_id) fromstudent_info sti left joinscore_info sci onsti.stu_idsci.stu_id l…...
更改chatglm认知
ChatGLM-Efficient-Tuning 下载源代码 下载ChatGLM-Efficient-Tuning 解压 创建虚拟环境 conda create --prefixD:\CondaEnvs\chatglm6btrain python3.10 cd D:\ChatGLM-Efficient-Tuning-main conda activate D:\CondaEnvs\chatglm6btrain安装所需要的包 pip install -r…...
WPF 界面命令绑定(MVVM结构)
1.创建模型数据类(M) /// <summary>/// 数据模型/// </summary>public class LoginDataModel{// 用户名private string _userName;public string UserName{get { return _userName; }set{_userName value;}}// 密码private string _passWor…...
常见手撕项目C++
常见手撕项目C 设计模式单例模式饿汉模式懒汉模式 策略模式策略接口实现具体的策略(虚函数重写)定义上下文用户调用 设计模式 单例模式 单例模式是一种常用的软件设计模式,其目的是确保一个类只有一个实例,并提供一个全局访问点来…...
创建一个批处理作业来处理大量数据,例如从数据库中读取数据并进行处理
创建一个批处理作业来处理大量数据,例如从数据库中读取数据并进行处理 要创建一个批处理作业来处理大量数据,您可以使用Spring Batch。Spring Batch是一个用于大规模批处理的框架,它提供了丰富的功能来处理复杂的批处理任务,如读…...
简单做网站用什么软件/谷歌seo优化排名
4.1~4.2节 R1.数据报,交换机基于链路层,路由器基于网络层。 R2.维护、更新转发状态信息。虚电路建立,数据传送,虚电路拆除。 R3. 转发是指将分组从一个输入链路接口转移到合适的输出链路端口的路由本地动作。 路由选择是指网络范围…...
wordpress 投稿 图片大小/百度权重是怎么来的
转载地址:点击打开链接 awk是一种编程语言,用于在Linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强…...
赣州市做网站设计/杭州seo公司
1、创建场景函数 var scenenew THREE.Scene();说明: 创建一个场景,所有的物体,容器都放在该场景中,并且只存在于一个唯一的场景。 2、创建相机函数 var cameranew THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeig…...
威海做网站多少钱/制作网站代码
什么是Mybatis?众所周知,MyBatis 是一款非常优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。不仅避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。还可以使用简单的 XML 或注解来配置和映射原生信息,将接口…...
学做网站快吗/百度店铺怎么开通
转载于:https://www.cnblogs.com/hdu-2010/p/5082382.html...
佛教网站大全网/办理培训机构需要具备的条件
1、在Java中,没有goto语句。因为大量使用goto语句会降低程序的可读性和可维护性,所以Java语言取消了goto的使用。同时,为了避免程序员自行使用goto所带来的混乱,Java语言仍将goto定义为一个关键字,但是没有定义任何语法…...