Linux--Socket编程TCP
前文:Socket套接字编程
TCP的特点
- 面向连接:TCP 在发送数据之前,必须先建立连接。
- 可靠性:TCP 提供了数据传输的可靠性。
- 面向字节流:TCP 是一个面向字节流的协议,这意味着 TCP 将应用程序交下来的数据看成是一连串的无结构的字节流。
TcpServer.hpp
创建一个Tcp服务端

代码
#pragma once#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<cstring>
#include<arpa/inet.h>
#include<unistd.h>
#include <sys/wait.h>
#include<functional>
#include<pthread.h>
#include"InetAddr.hpp"
#include"Log.hpp"
#include"Threadpool.hpp"enum
{SOCKET_ERROR = 1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR
};const static int defaultsockfd = -1;//默认文件描述符
const static int gbacklog = 16;//默认最大连接数using task_t=std::function<void*()>; //任务函数的类型(V3)
class TcpServer;
//线程类型数据
class ThreadData
{
public:ThreadData(int fd,InetAddr addr,TcpServer* s):sockfd(fd),clientaddr(addr),self(s){}
public:int sockfd;//文件描述符InetAddr clientaddr;//客户端地址TcpServer* self;//服务端
};
class TcpServer
{
public:TcpServer(int port):_port(port),_listensock(defaultsockfd),_isrunning(false){}void InitServer(){//1.创建字节流套接字_listensock=socket(AF_INET,SOCK_STREAM,0);if(_listensock<0){LOG(FATAL, "socket error");exit(SOCKET_ERROR);}LOG(DEBUG, "socket create success, sockfd is : %d\n", _listensock);//2.bindstruct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(_port);local.sin_addr.s_addr=INADDR_ANY;int n= ::bind(_listensock,(struct sockaddr*)&local,sizeof(local));if(n<0){LOG(FATAL, "bind error\n");exit(BIND_ERROR);}LOG(DEBUG, "bind success, sockfd is : %d\n", _listensock);//3.监听客户端,等待被连接n=listen(_listensock,gbacklog);if(n<0){LOG(FATAL, "listen error");exit(LISTEN_ERROR);}LOG(DEBUG, "listen success, sockfd is : %d\n", _listensock);}//将接收到的数据进行处理,完成对应服务void Service(int sockfd,InetAddr client){LOG(DEBUG, "get a new link, info %s %d ,fd: %d \n ",client.Ip().c_str(),client.Port(),sockfd);std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]# ";while(true){char inbuffer[1024];ssize_t n = read(sockfd,inbuffer,sizeof(inbuffer)-1);//读取数据if(n>0){inbuffer[n]=0;std::cout<<clientaddr<<inbuffer<<std::endl;//打印对应的数据std::string echo_string = "[server echo]# ";echo_string+=inbuffer;write(sockfd,echo_string.c_str(),echo_string.size());//返回给客户端}else if(n==0) //client退出并且关闭连接了{LOG(INFO, "%s quit\n", clientaddr.c_str());break;}else{LOG(ERROR, "read error\n");break;}}close(sockfd); }//线程的处理函数static void* HandlerSock(void* args){pthread_detach(pthread_self());//线程分离ThreadData* td=static_cast<ThreadData*>(args);//创建对应线程数据类型td->self->Service(td->sockfd,td->clientaddr);delete td;return nullptr;}//服务器循环运行着void Loop(){_isrunning=true;while(_isrunning){struct sockaddr_in peer;//sock地址peersocklen_t len=sizeof(peer);//要先通过连接才能够进行通信int sockfd=::accept(_listensock,(struct sockaddr *)&peer,&len);//这里的监听sock和sockfd是不同的if(sockfd<0){LOG(WARNING, "accept error\n");continue;}//Version0 这种版本只能接收一次需求,无法多客户端连接// Service(sockfd,InetAddr(peer));//Version1 多进程// pid_t id=fork();// if(id>0)// {// //子进程负责连接,父进程负责监听,// close(_listensock);// if(fork()>0) exit(0);// //孙进程负责服务,由于子进程连接之后,子进程会进行回收,因此孙进程称为孤儿进程,之后不受子进程的影响// //类似线程分离,是独立的,之后受系统进行回收// Service(sockfd,InetAddr(peer));// exit(0);// }// //父进程只负责监听,不需要进行连接// close(sockfd);// waitpid(id,nullptr,0);//Version2:采用多线程pthread_t t;ThreadData* td=new ThreadData(sockfd,peer,this);pthread_create(&t,nullptr,HandlerSock,td);//将线程分离//Version3:线程池//task_t t = std::bind(&TcpServer::Service,this,sockfd,InetAddr(peer));//ThreadPool<task_t>::GetInstance()->Enqueue(t);}_isrunning=false;}~TcpServer(){if(_listensock>defaultsockfd){close(_listensock);}}private:uint16_t _port;//端口号int _listensock;//监听的文件描述符bool _isrunning;//启动
};
解释

初始化服务端,主要完成套接字的创建绑定,已经完成对应的监听客户端,因为Tcp是有连接的,所以需要监听客户端是否有请求连接的需求;
SOCK_STREAM表示字节流
gbacklog:这个参数定义了内核应该为相应套接字排队的最大连接数。这个值至少为0;其实际值由系统限制,可以通过sysctl命令的net.core.somaxconn参数查看和设置。需要注意的是,这个值并不是指系统能处理的并发连接数,而是内核中等待accept(处理的连接队列的最大长度。

启动服务器之后,通过循环让服务端不断运行着,在循环里面,服务端可能接收到多个客户端请求的连接,所以accpet要在循环中不断接收看是否有对应的连接;
连接完之后通过Service服务函数完成双方的通信

在Loop中,循环表示接收多个客户端,而Service中,循环表示每个服务端与客户端的通信保持;
由于tcp是面向字节流的,所以可以利用文件描述符的性质,运用read函数,读取对应的发送端数据.
当n大于0时,表示对方有数据发送,处理完信息后反馈给对方;
当n==0,表示sockfd被关闭了,也就是连接被断开了;
当n小于0时,表示出现错误;
如果一直没有发送数据,那么会在read函数这里发生阻塞;

而对于服务的处理,这里有多种方法,如果直接使用Service函数的话,是不可行的,因为这样无法多客户端连接:



通过多进程的方法,让父进程只负责监听,子进程负责连接,孙进程负责服务,由于孙进程是孤儿进程,相当于线程分离,这样处理服务时就不会受到父子进程的影响了;也就能完成多客户端的通信了;

直接通过多线程的方法,将创建的线程进行分离,完成对应的服务任务
main.cc
#include"TcpServer.hpp"
#include<memory>void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " local_port\n" << std::endl;
}
// ./main.cc 8080
int main(int argc,char* argv[])
{if(argc!=2){Usage(argv[0]);return 1;}EnableScreen();//打印到屏幕uint16_t port=std::stoi(argv[1]);//获取端口号std::unique_ptr<TcpServer> tsvr=std::make_unique<TcpServer>(port);//服务端的指针tsvr->InitServer();//初始化tsvr->Loop();//循环运行return 0;}
TcpClient.cc
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<cstring>void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " serverip serverport\n"<< std::endl;
}
// ./TcpClient.cc 127.0.0.1 8080
int main(int argc,char* argv[])
{if(argc!=3){Usage(argv[0]);exit(1);}std::string serverip=argv[1];//服务端ipuint16_t serverport=std::stoi(argv[2]);//服务端端口号int sockfd = socket(AF_INET, SOCK_STREAM, 0);//创建套接字if (sockfd < 0){std::cerr << "socket error" << std::endl;exit(2);}struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(serverport);server.sin_addr.s_addr=inet_addr(serverip.c_str());//连接服务端int n=connect(sockfd,(struct sockaddr*)&server,sizeof(server));if(n<0){std::cerr << "connect error" << std::endl;exit(3);}while(true){std::cout<<"Please Enter# ";std::string outstring;getline(std::cin,outstring);//发送对应数据ssize_t s=send(sockfd,outstring.c_str(),outstring.size(),0);if(s>0){char inbuffer[1024];ssize_t m=recv(sockfd,inbuffer,sizeof(inbuffer)-1,0);//接收对应数据if(m>0){inbuffer[m]=0;std::cout<<inbuffer<<std::endl;}else{break;}}else{break;}}close(sockfd);return 0;
}
结果

相关文章:
Linux--Socket编程TCP
前文:Socket套接字编程 TCP的特点 面向连接:TCP 在发送数据之前,必须先建立连接。可靠性:TCP 提供了数据传输的可靠性。面向字节流:TCP 是一个面向字节流的协议,这意味着 TCP 将应用程序交下来的数据看成是…...
Android Studio导入源码
在有源码并且编译环境可用的情况下: 1.生成导入AS所需的配置文件 在源码的根目录执行以下命令: source build/ensetup.sh lunch 要编译的项目 make idegen //这一步会生成out/host/linux-x86/framework/idegen.jar development/tools/idegen/idegen.sh…...
UE5 UE4 使用python进行编辑器操作
使用UE 4.25以上版本后,python代码改动相对较少。 如下类库在4.20/21/22等早起版本不适用,建议查询UE的python文档 unreal.EditorAssetLibrary 1.获取当前选中的资源(Content中) # 获取当前选中的资产selected_assets unreal.E…...
区块链技术在智能城市中的创新应用探索
随着全球城市化进程的加速和信息技术的快速发展,智能城市成为了未来城市发展的重要方向。在智能城市建设中,区块链技术作为一种去中心化、安全和透明的分布式账本技术,正逐渐展现出其在优化城市管理、提升公共服务和增强城市安全性方面的潜力…...
解决mysql事件调度器重启服务后自动失效的问题
前段时间为通过mysql事件生成测试数据,今天发现数据在10:57后停止了CREATE EVENT IF NOT EXISTS insert_random_data ON SCHEDULE EVERY 10 SECOND DO INSERT INTO test (createtime, random_number) VALUES (NOW(), FLOOR(RAND() * 100));检查事件状态&#…...
mybatis开启二级缓存
例子 mybatis-config.xml <configuration><settings><setting name"cacheEnabled" value"true"/></settings><environments default"development"><environment id"development"><transacti…...
Oracle大型数据库管理(一)Oracle大型数据库管理全面指南
文章目录 Oracle大型数据库管理全面指南引言1. Oracle数据库概述1.1 什么是Oracle数据库1.2 Oracle数据库的主要特点 2. Oracle数据库部署2.1 安装前的准备工作2.1.1 操作系统要求2.1.2 硬件要求2.1.3 软件环境要求 2.2 Oracle数据库的安装2.2.1 用户和目录的创建2.2.2 安装Ora…...
Arcgis中查找空间距离范围内字段相等的数据
背景 目前有两份空间点数据,需要通过点数据1查找100米空间距离范围内点数据2中与点数据1某个字段相同的数据 步骤 1、arcgis中加载数据 2、空间连接 结果,从下面这两个字段可以看出,点数据1在100米空间距离范围内有多个点数据2 3、选择数…...
js中map属性
JavaScript中的Map对象保存键值对,并且能够记住键的原始插入顺序 以下是关于如何在JavaScript中使用Map对象的博客文章概要: 一、创建和初始化Map对象 使用new Map()构造函数可以创建一个新的Map对象。你还可以在构造函数中传入一个可迭代对象&#x…...
CS224W—03 GNN
CS224W—03 GNN 回顾 快速回顾一下上一讲的内容。我们学到的关键概念是节点嵌入(Node Embedding)。我们的直觉是将网络中的节点编码到低维向量空间中。我们希望学习一个接受输入图的函数 f f f,并将其嵌入到低维节点嵌入空间中。在这里&am…...
库存超卖问题解决方式
文章目录 超卖问题解决方式什么是库存超卖问题?乐观锁和悲观锁的定义超卖问题解决方式一、悲观锁1.jvm单机锁2.通过使用mysql的行锁,使用一个sql解决并发访问问题3.使用mysql的悲观锁解决4. 使用redis分布式锁来解决 二、乐观锁解决1.版本号2. CAS法&…...
30岁决心转行,AI太香了
今天是一篇老学员的经历分享,此时的王同学在大洋彼岸即将毕业,手握多家北美大厂offer,一片明媚。谁能想到王同学的转码之路竟始于一场裁员,这场访谈拉开了他的回忆。 最近总刷到一些关于转行的话题,很多刚毕业的同学喜…...
C#知识|文件与目录操作:目录的操作
哈喽,你好啊,我是雷工! 前边学习了文件的删除、复制、移动,接下来学习目录的操作。 以下为学习笔记。 01 效果演示 1.1、显示指定目录下的所有文件 在左侧的文本框中显示出F:\F004-C#目录下的所有文件, 演示效果: 1.2、显示指定目录下的所有子文件 在左侧的文本框中显…...
从零到一:用Go语言构建你的第一个Web服务
使用Go语言从零开始搭建一个Web服务,包括环境搭建、路由处理、中间件使用、JSON和表单数据处理等关键步骤,提供丰富的代码示例。 关注TechLead,复旦博士,分享云服务领域全维度开发技术。拥有10年互联网服务架构、AI产品研发经验、…...
塔子哥的环游之旅-腾讯2023笔试(codefun2000)
题目链接 塔子哥的环游之旅-腾讯2023笔试(codefun2000) 题目内容 塔子哥是一位热衷旅游的程序员。他所在的国家共有 n 个城市,编号从 1 到 n。这些城市之间有 m 条双向的交通线路,分别为飞机线路和火车线路。塔子哥起始位于编号为 1 的城市,他计划前往编号为 n 的城市进行旅游…...
力扣SQL50 换座位
Problem: 626. 换座位 👨🏫 参考题解 Code SELECT(CASEWHEN MOD(id, 2) ! 0 AND counts ! id THEN id 1WHEN MOD(id, 2) ! 0 AND counts id THEN idELSE id - 1END) AS id,student FROMseat,(SELECTCOUNT(*) AS countsFROMseat) AS seat_counts O…...
SOPHGO算能科技BM1684芯片修改内存布局
目录 1 问题由来 2 下载memory_edit工具 3 查看当前内存配置 3 修改内存布局 4 替换生效 参考文献: 1 问题由来 我在算能SE5盒子上开发的时候,明显感觉很慢,然后看了下cpu内存竟然只有2.6G 但是这个盒子出厂默认是12G的,于…...
CUDA实现矩阵乘法的性能优化策略
本人主要参考了https://zhuanlan.zhihu.com/p/435908830,https://zhuanlan.zhihu.com/p/410278370,https://zhuanlan.zhihu.com/p/518857175 ,下面的代码均是本人实现 矩阵乘法的easy实现-V1 C = A B , A ∈ R M K , B ∈ R K...
element ui 修改table筛选按钮为自定义按钮
element ui 修改table筛选按钮为自定义按钮 前些时间做项目的时候,有个需求是,嫌elementui 自定的筛选按钮 下拉的小三角不好看,需要自定义按钮。 具体的实现方法如下: 从阿里的图片库引入自己想要的图标。在需要修改按钮的vue页…...
面向对象编程:一切皆对象
面向对象(OOP)是一种编程范式,它使用对象来设计软件。对象可以包含数据和代码:数据代表对象的状态,而代码代表操作数据的方式。在面向对象编程中,一切皆对象,这意味着将现实世界事务使用类与实例来模拟,如灯࿰…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
基于 HTTP 的单向流式通信协议SSE详解
SSE(Server-Sent Events)详解 🧠 什么是 SSE? SSE(Server-Sent Events) 是 HTML5 标准中定义的一种通信机制,它允许服务器主动将事件推送给客户端(浏览器)。与传统的 H…...
Spring是如何实现无代理对象的循环依赖
无代理对象的循环依赖 什么是循环依赖解决方案实现方式测试验证 引入代理对象的影响创建代理对象问题分析 源码见:mini-spring 什么是循环依赖 循环依赖是指在对象创建过程中,两个或多个对象相互依赖,导致创建过程陷入死循环。以下通过一个简…...
TMC2226超静音步进电机驱动控制模块
目前已经使用TMC2226量产超过20K,发现在静音方面做的还是很不错。 一、TMC2226管脚定义说明 二、原理图及下载地址 一、TMC2226管脚定义说明 引脚编号类型功能OB11电机线圈 B 输出 1BRB2线圈 B 的检测电阻连接端。将检测电阻靠近该引脚连接到地。使用内部检测电阻时,将此引…...
