当前位置: 首页 > news >正文

Linux网络编程——tcp套接字

文章目录

    • 主要代码
    • 关于构造
    • listen监听
    • accept
    • telnet测试
    • 读取信息
    • 掉线重连
    • 翻译服务器演示

本章Gitee仓库:tcp套接字

主要代码

客户端:

#pragma once#include"Log.hpp"#include<iostream>
#include<cstring>#include<sys/wait.h>
#include<unistd.h>
#include<signal.h>
#include<pthread.h>#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>#include"threadPool.hpp"
#include"Task.hpp"const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 5;  //不要设置太大
Log log;enum{USAGE_ERR = 1,SOCKET_ERR,BIND_ERR,LITSEN_ERR
};
class TcpServer;class ThreadData
{
public:ThreadData(int fd, const std::string &ip, const uint16_t &port, TcpServer *t):t_sockfd_(fd), t_clientip_(ip), t_clientport_(port), t_tsvr_(t){}
public:int t_sockfd_;std::string t_clientip_;uint16_t t_clientport_;TcpServer *t_tsvr_; //需要this指针
};class TcpServer
{public:TcpServer(const uint16_t &port, const std::string &ip = defaultip):listensockfd_(defaultfd),port_(port),ip_(ip){}//初始化服务器void Init(){//创建套接字listensockfd_ = socket(AF_INET, SOCK_STREAM, 0); //sock_stream提供字节流服务--tcpif(listensockfd_ < 0){log(Fatal, "create socket, errno: %d, errstring: %s",errno, strerror(errno));exit(SOCKET_ERR);}log(Info, "create socket success, sockfd: %d",listensockfd_);int opt = 1;setsockopt(listensockfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));  //防止偶发性服务器无法进行立即重启//本地套接字信息struct sockaddr_in local;memset(&local, 0, sizeof(local));//填充网络信息local.sin_family = AF_INET;local.sin_port = htons(port_);inet_aton(ip_.c_str(), &(local.sin_addr));//bindint bd = bind(listensockfd_, (struct sockaddr*)&local, sizeof(local));if(bd < 0){log(Fatal, "bind error, errno: %d, errstring: %s",errno, strerror(errno));exit(BIND_ERR);}log(Info, "bind success");//tcp面向连接, 通信之前要建立连接//监听if(listen(listensockfd_, backlog) < 0){log(Fatal, "listen error, errno: %d, errstring: %s",errno, strerror(errno));exit(LITSEN_ERR);}log(Info, "listen success");}static void *Routine(void *args){pthread_detach(pthread_self());//子线程无需关闭文件描述符ThreadData *td = static_cast<ThreadData*>(args);td->t_tsvr_->Service(td->t_sockfd_, td->t_clientip_, td->t_clientport_);delete td;}void Start(){signal(SIGPIPE, SIG_IGN);threadPool<Task>::GetInstance()->Start();//signal(SIGCHLD, SIG_IGN);  //直接忽略进程等待 V2log(Info, "server is running...");while(true){//获取新链接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensockfd_, (struct sockaddr*)&client, &len);if(sockfd < 0){log(Warning, "accpet error, errno: %d, errstring: %s",errno, strerror(errno));continue;}uint16_t clientport = ntohs(client.sin_port);char clientip[32];inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));log(Info, "get a new link..., sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip, clientport);//根据新链接进行通信//V1--单进程//Service(sockfd, clientip, clientport);//close(sockfd);//V2--多进程// pid_t id = fork();// if(id == 0)// {//     //child//     close(listensockfd_);  //子进程可以看到父进程的文件描述符表,关闭不需要的 //     if(fork() > 0)  exit(0);//父进程创建的子进程直接退出//     Service(sockfd, clientip, clientport);  //孙子进程执行, 由于孙子的父进程退出, 由系统领养//     close(sockfd);//     exit(0);// }// //father// close(sockfd);  //存在引用计数,不会这个关闭这个文件// pid_t tid = waitpid(id, nullptr, 0);// (void)tid;//V3--多线程(创建进程成本较高,换线程)// ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);// pthread_t tid;// pthread_create(&tid, nullptr, Routine, td);//pthread_join(tid, nullptr);   //已进行线程分离,无需等待(并发执行)//V4--线程池Task t(sockfd, clientip, clientport);threadPool<Task>::GetInstance()->Push(t);//sleep(1); }}void Service(int sockfd, const std::string &clientip, const uint16_t &clientport){char buffer[4096];while(true){ssize_t n = read(sockfd, buffer, sizeof(buffer));if(n > 0){buffer[n] = 0;std::cout << "client say# " << buffer << std::endl;std::string echo_str = "tcpserver echo# ";echo_str += buffer;write(sockfd, echo_str.c_str(), echo_str.size());}else if(n == 0){log(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);break;}else{log(Warning, "read error, sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip.c_str(), clientport);break;}memset(buffer, 0, sizeof(buffer));}}~TcpServer(){}
private:int listensockfd_;uint16_t port_;std::string ip_;
};

客户端:

#include<iostream>
#include<cstring>
#include<unistd.h>#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>void Usage(const std::string &proc)
{std::cout << "\n\tUsage: " << proc << "serverip serverport" << std::endl;
}int main(int argc, char *argv[])
{if(argc != 3){Usage(argv[0]);exit(1);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);// 填充信息struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));//连接模块while (true){int sockfd = 0;int cnt = 5;bool isreconnect = false;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;return 1;}do{// tcp客户端也无需显示bind// 向目标发起连接(connect的时候进行自动随机bind)int cn = connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (cn < 0){isreconnect = true;cnt--;  //重连5秒std::cerr << "connet error, reconnect: " << cnt << std::endl;close(sockfd);sleep(1);   //每隔一秒重连一次}else{break;}}while(cnt && isreconnect);if(cnt == 0){std::cerr << "server offline..." << std::endl;break;}//服务模块//while (true){std::string message;std::cout << "Please Enter# ";std::getline(std::cin, message);if (message.empty())continue;int wn = write(sockfd, message.c_str(), message.size());if (wn < 0){std::cerr << "write error" << std::endl;//break;}char inbuffer[4096];int rn = read(sockfd, inbuffer, sizeof(inbuffer));if (rn > 0){inbuffer[rn] = 0;std::cout << inbuffer << std::endl;}else{//break;}}close(sockfd);}return 0;
}

关于构造

关于构造和初始化,可以直接在构造的时候,将服务器初始化,那为什么还要写到init初始化函数里面呢?

构造尽量简单一点,不要做一些“有风险”的操作。

listen监听

tcp是面向连接的,通信之前要建立连接,服务器处于等待连接到来的状态:

#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);

image-20240205161303727

accept

获取新链接:

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

后两个参数输出型参数,获取对方的信息

这里返回也是一个套接字,这和最开始创建的listensockfd_有什么区别呢?

这就好比去吃饭,门口有一个拉客的,问“帅哥,来不来我们这里吃饭啊”,如果你去了,那就是“欢迎光临,几位呀”,你回答“我和我女朋友”,然后这个人大喊“两位客人,来一个服务员”,这时候就来了一个服务员招呼你坐下,然后给你菜单,点完菜之后给你上菜;在这个期间站在门口的拉客的人,一直在招揽客人,有人来就喊服务员招招待,人家不来就继续拉。

listensockdf_就是这个拉客的,真正给我们提供服务的是accept返回的

telnet测试

telnet可以对指定服务的远程连接

image-20240205192444936

127.0.0.1本地环回,再加上端口号就可以测试了

ctrl + ],然后回车

读取信息

tcp是面向字节流的,管道是面向字节流的、读取普通文件也是面向字节流的,所以可以采用read进行读取。

掉线重连

当读端关闭之后,系统会杀掉写端,采用signal(SIGPIPE, SIG_IGN)忽略这个信号

翻译服务器演示

GIF 2024-2-11 20-17-30

相关文章:

Linux网络编程——tcp套接字

文章目录 主要代码关于构造listen监听accepttelnet测试读取信息掉线重连翻译服务器演示 本章Gitee仓库&#xff1a;tcp套接字 主要代码 客户端&#xff1a; #pragma once#include"Log.hpp"#include<iostream> #include<cstring>#include<sys/wait.h…...

【计算机网络】协议层次及其服务模型

协议栈&#xff08;protocol stack&#xff09; 物理层链路层网络层运输层应用层我们自顶向下&#xff0c;所以从应用层开始探究应用层 协议 HTTP 提供了WEB文档的请求和传送SMTP 提供电子邮件报文的传输FTP 提供两个端系统之间的文件传输报文&#xff08;message&#xff09;是…...

prometheus之redis_exporter部署

下载解压压缩包 mkdir /opt/redis_exporter/ cd /opt/redis_exporter/ wget http://soft.download/soft/linux/prometheus/redis_exporter/redis_exporter-v1.50.0.linux-amd64.tar.gz tar -zxvf redis_exporter-v1.50.0.linux-amd64.tar.gz ln -s /opt/redis_exporter/redis_…...

js 解构赋值

搬运&#xff1a;JavaScript系列之解构赋值_js解构赋值-CSDN博客...

Vivado用ILA抓波形保存为CSV文件

将ILA观察到的波形数据捕获为CSV文件&#xff0c;抓10次&#xff0c;把文件合并&#xff0c;把源文件删除 运行方法&#xff1a;Vivado的 Tcl console 窗口输入命令 set tcl_dir F:/KLD_FPGA/Code/sim set tcl_filename TCL_ILA_TRIG_V1.2.tcl source $tcl_dir/$tcl_filenam…...

微软AD域替代方案,助力企业摆脱hw期间被攻击的窘境

在红蓝攻防演练&#xff08;hw行动&#xff09;中&#xff0c;AD域若被攻击成功&#xff0c;是其中一个扣分最多的一项内容。每年&#xff0c;宁盾都会接到大量AD在hw期间被攻击&#xff0c;甚至是被打穿的企业客户。过去&#xff0c;企业还会借助2FA双因子认证加强OA、Exchang…...

Git教程I

Git教程I 本地Git创建git仓库将修改存到暂存区将暂存区提交到当前分支查看提交历史回退版本恢复到更晚的版本创建新分支切换分支简单的分支合并冲突分支合并不使用fast forward: --no-ff 远程Git连接远程仓库将本地分支上传到远程仓库从远程仓库拉取 本地Git 学习如何使用本地…...

containerd中文翻译系列(十)镜像验证

下面将介绍默认的 "bindir"ImageVerifier插件实现。 要启用图像验证&#xff0c;请在 containerd 配置中添加类似下面的一段&#xff1a; [plugins][plugins."io.containerd.image-verifier.v1.bindir"]bin_dir "/opt/containerd/image-verifier/b…...

假期day9(2024/2/14)

获取数据库查询的值并调用值使用函数&#xff1a;sqlite3_get_table 在回调函数中获取数据库查询值&#xff0c;无法在其他函数调用&#xff1a;使用函数sqlite3_exec(db, sql, select_callback, &flag, &errmsg&#xff09; 创建表 create table if not exists 表名…...

Leetcode 674 最长连续递增序列

题意理解&#xff1a; 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 nums[i…...

力扣题目训练(8)

2024年2月1日力扣题目训练 2024年2月1日力扣题目训练404. 左叶子之和405. 数字转换为十六进制数409. 最长回文串116. 填充每个节点的下一个右侧节点指针120. 三角形最小路径和60. 排列序列 2024年2月1日力扣题目训练 2024年2月1日第八天编程训练&#xff0c;今天主要是进行一些…...

理解JAVA EE设计模式

理解JAVA EE设计模式 在Web应用程序的设计和开发阶段,开发人员在开发类似的项目时可能会遇到相似的问题。每名开发人员可能会遇到的问题找出不同或相似的解决方案。但是,这导致一些时间和精力浪费在为相似的问题寻找解决方案上。因此,要啊节省时间和精力,需要记录常见问题…...

GEE:梯度提升树(Gradient Boosting Tree)回归教程(样本点、特征添加、训练、精度、参数优化)

作者:CSDN @ _养乐多_ 对于分类问题,这个输出通常是一个类别标签 ,而对于回归问题,输出通常是一个连续的数值。回归可以应用于多种场景,包括预测土壤PH值、土壤有机碳、土壤水分、碳密度、生物量、气温、海冰厚度、不透水面积百分比、植被覆盖度等。 本文将介绍在Google…...

k8s-资源限制与监控 15

资源限制 上传实验所需镜像 Kubernetes采用request和limit两种限制类型来对资源进行分配。 request(资源需求)&#xff1a;即运行Pod的节点必须满足运行Pod的最基本需求才能 运行Pod。 limit(资源限额)&#xff1a;即运行Pod期间&#xff0c;可能内存使用量会增加&#xff0…...

【Ubuntu】在.bashrc文件中误设置环境变量补救方法

这里是vim也不在PATH中了&#xff0c;因为 解决方法就是在输入vim之后提示的vim路径下用vim打开该文件&#xff0c;然后改回来...

Imgui(1) | 基于imgui-SFML改进自由落体小球

Imgui(1) | 基于imgui-SFML改进自由落体小球 0. 简介 使用 SFML 做2D图形渲染的同时&#xff0c;还想添加一个按钮之类的 GUI Widget, 需要用 Dear Imgui。由于 Imgui 对于2D图形渲染并没有提供类似 SFML 的 API, 结合它们两个使用是一个比较好的方法, 找到了 imgui-SFML 这个…...

Linux-Vim的使用,快速入门Vim,Linux入门教程,精讲Linux

Vim的三种模式 输入模式&#xff0c;键入 i 或 a 或 o 都可以进入输入模式。 普通模式&#xff0c;打开Vim默认的模式。 命令模式&#xff0c;键入 : 进入命令模式。 注意&#xff1a;按下 ESC 可以从输入模式或命令模式退回到普通模式 退出 vim &#xff0c;需要在普通模式下…...

目标检测 | 卷积神经网络(CNN)详细介绍及其原理详解

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种深度学习模型&#xff0c;主要用于图像识别和计算机视觉任务。它的设计灵感来自于生物学中视觉皮层的工作原理。CNN的核心思想是通…...

机器人学、机器视觉与控制 上机笔记(第一版译文版 2.1章节)

机器人学、机器视觉与控制 上机笔记&#xff08;第一版译文版 2.1章节&#xff09; 1、前言2、本篇内容3、代码记录3.1、新建se23.2、生成坐标系3.3、将T1表示的变换绘制3.4、完整绘制代码3.5、获取点*在坐标系1下的表示3.6、相对坐标获取完整代码 4、结语 1、前言 工作需要&a…...

关于vue2+antd 信息发布后台不足的地方

有的写法可以cv 1.序号递增 {title: "序号",customRender: (text, record, index) > ${index 1},align: "center",}, 2.关于类型 {title: "类型",dataIndex: "type",align: "center",customRender: function (t) {sw…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...