Linux——网络通信TCP通信常用的接口和tcp服务demo
文章目录
- TCP通信所需要的套接字
- socket()
- bind()
- listen()
- accept
- connect()
- 封装TCP socket
TCP通信所需要的套接字
socket()
socket()函数主要作用是返回一个描述符,他的作用就是打开一个网络通讯端口,返回的这个描述符其实就可以理解为一个文件描述符,tcp在通讯的时候是会开辟一个缓存空间的,我们发送和读取消息可以理解为在这个缓存空间中进行的。因此这里我们可以知道我们可以直接用write和read函数进行消息的写入和读取,如果socket()调用出错则返回-1;
对于IPv4, family参数指定为AF_INET;
对于TCP协议,type参数指定为SOCK_STREAM, 表示面向流的传输协议
protocol参数的介绍从略,指定为0即可。
代码如下以ipv4协议为例
int socketfd=socket(AF_INET,SOCK_STREAM,0);
bind()
bind()函数的作用是为了让socket返回的描述符与端口号进行绑定在bind函数之前我们还需要做一个工作就是将我们的信息存入一个结构体sockaddr_in中,struct sockaddr *是一个通用指针类型,myaddr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度

我们的程序中对myaddr参数是这样初始化的:
sockaddr_in local;
bzero(&local, sizeof(local));//将整个结构体清0
local.sin_port = htons(port_);//porty_是我们的端口号这里是将这个端口号转化为网络序列一般我们的端口号都设置为8000以上
local.sin_family = AF_INET;//设置地址类型为AF_INET
inet_aton(ip_.c_str(), &(local.sin_addr));//网络地址为INADDR_ANY, 这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP 地址, 这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP 地址;
listen()

liasten函数生命socketfd正处于监听状态并且最多可以允许backlog个客户端处于连接等待状态如果收到更多连接请求就会忽略
listen成功返回0 失败则是-1
accept

accept函数是为了接受来自客户端的连接请求的函数它是在三次握手之后发挥作用,这里也会有一些问题比如说accept发挥作用的时候此时并没有客户发送连接请求该怎么办呢?这里会陷入阻塞等待的状态也就是一直等到有连接请求为止。
connect()

客户端需要调用connect()连接服务器;
connect和bind的参数形式一致, 区别在于bind的参数是自己的地址, 而connect的参数是对方的地址;
connect()成功返回0,出错返回-1
封装TCP socket
tcp_socket.hpp
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <cassert>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
#define CHECK_RET(exp) if (!(exp)) {\return false;\
}
class TcpSocket {
public:TcpSocket() : fd_(-1) { }TcpSocket(int fd) : fd_(fd) { }bool Socket() {fd_ = socket(AF_INET, SOCK_STREAM, 0);if (fd_ < 0) {perror("socket");return false;}printf("open fd = %d\n", fd_);return true;}bool Close() const {close(fd_);printf("close fd = %d\n", fd_);return true;}bool Bind(const std::string& ip, uint16_t port) const {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 = bind(fd_, (sockaddr*)&addr, sizeof(addr));if (ret < 0) {perror("bind");return false;}return true;}bool Listen(int num) const {int ret = listen(fd_, num);if (ret < 0) {perror("listen");return false;}return true;}bool Accept(TcpSocket* peer, std::string* ip = NULL, uint16_t* port = NULL) const {sockaddr_in peer_addr;socklen_t len = sizeof(peer_addr);int new_sock = accept(fd_, (sockaddr*)&peer_addr, &len);if (new_sock < 0) {perror("accept");return false;}printf("accept fd = %d\n", new_sock);peer->fd_ = new_sock;if (ip != NULL) {*ip = inet_ntoa(peer_addr.sin_addr);}if (port != NULL) {*port = ntohs(peer_addr.sin_port);}return true;}bool Recv(std::string* buf) const {buf->clear();char tmp[1024 * 10] = {0};// [注意!] 这里的读并不算很严谨, 因为一次 recv 并不能保证把所有的数据都全部读完// 参考 man 手册 MSG_WAITALL 节. ssize_t read_size = recv(fd_, tmp, sizeof(tmp), 0);if (read_size < 0) {perror("recv");return false;}if (read_size == 0) {return false;}buf->assign(tmp, read_size);return true;}bool Send(const std::string& buf) const {ssize_t write_size = send(fd_, buf.data(), buf.size(), 0);if (write_size < 0) {perror("send");return false;}return true;}bool Connect(const std::string& ip, uint16_t port) const {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");return false;}return true;}int GetFd() const {return fd_;}private:int fd_;
};
tcp_server.hpp
#pragma once
#include <functional>
#include "tcp_socket.hpp"
typedef std::function<void (const std::string& req, std::string* resp)> Handler;
class TcpServer {
public:TcpServer(const std::string& ip, uint16_t port) : ip_(ip), port_(port) {}bool Start(Handler handler) {// 1. 创建 socket;CHECK_RET(listen_sock_.Socket());// 2. 绑定端口号CHECK_RET(listen_sock_.Bind(ip_, port_));// 3. 进行监听CHECK_RET(listen_sock_.Listen(5));// 4. 进入事件循环for (;;) {// 5. 进行 acceptTcpSocket new_sock;std::string ip;uint16_t port = 0;if (!listen_sock_.Accept(&new_sock, &ip, &port)) {continue;}printf("[client %s:%d] connect!\n", ip.c_str(), port);// 6. 进行循环读写for (;;) {std::string req;// 7. 读取请求. 读取失败则结束循环bool ret = new_sock.Recv(&req);if (!ret) {printf("[client %s:%d] disconnect!\n", ip.c_str(), port);// [注意!] 需要关闭 socketnew_sock.Close();break;}// 8. 计算响应std::string resp;handler(req, &resp);// 9. 写回响应new_sock.Send(resp);
printf("[%s:%d] req: %s, resp: %s\n", ip.c_str(), port,req.c_str(), resp.c_str());}}return true;}
private:TcpSocket listen_sock_;std::string ip_;uint64_t port_;
};
我们开开心心的在一起
相关文章:
Linux——网络通信TCP通信常用的接口和tcp服务demo
文章目录 TCP通信所需要的套接字socket()bind()listen()acceptconnect() 封装TCP socket TCP通信所需要的套接字 socket() socket()函数主要作用是返回一个描述符,他的作用就是打开一个网络通讯端口,返回的这个描述符其实就可以理解为一个文件描述符&a…...
【web | CTF】反序列化打法
天命:因为是php的上古版本,所以本机无法复现,只能用归纳法解决,就是题海战术找相同点,fuzz来测试新的题目 题目一:绕过正则和绕过__wakeup函数,private属性 【web | CTF】攻防世界 Web_php_uns…...
如何在Linux搭建Inis网站,并发布至公网实现远程访问【内网穿透】
如何在Linux搭建Inis网站,并发布至公网实现远程访问【内网穿透】 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道(云端设置)2.3.…...
YOLOv9来了! 使用可编程梯度信息学习你想学的内容, v7作者新作!【文献速读】
YOLOv9文献速读,本文章使用 GPT 4.0 和 Ai PDF 工具完成。 文章地址:https://arxiv.org/pdf/2402.13616.pdf 文章目录 文章简介有哪些相关研究?如何归类?谁是这一课题在领域内值得关注的研究员?论文试图解决什么问题&a…...
【鸿蒙 HarmonyOS 4.0】网络请求
一、介绍 资料来自官网:文档中心 网络管理模块主要提供以下功能: HTTP数据请求:通过HTTP发起一个数据请求。WebSocket连接:使用WebSocket建立服务器与客户端的双向连接。Socket连接:通过Socket进行数据传输。 日常…...
QT中的多线程有什么作用?
概述 在学习QT线程的时候我们首先要知道的是QT的主线程,也叫GUI线程,意如其名,也就是我们程序的最主要的一个线程,主要负责初始化界面并监听事件循环,并根据事件处理做出界面上的反馈。但是当我们只限于在一个主线程上…...
redis最佳实践
原则:redis希望存储的是热点数据,尽量可以在一天内访问到。 最佳实践 选择合适的数据结构 redis有String、Hash、Set、SortedSet、List等结构,主要依据业务需要进行选择 string:几乎所有数据都可以用string存储,但是最好适用于…...
架构师技能9-深入mybatis:Creating a new SqlSession到查询语句耗时特别长
开篇语录:以架构师的能力标准去分析每个问题,过后由表及里分析问题的本质,复盘总结经验,并把总结内容记录下来。当你解决各种各样的问题,也就积累了丰富的解决问题的经验,解决问题的能力也将自然得到极大的…...
【JavaEE】_HTTP请求报头header
目录 1. Host 2. Content-Length与Content-Type 2.1 Content-Length 2.2 Content-Type 3. User-Agent(UA) 4. Referer 5. Cookie header的整体格式是“键值对”结构,一行是一个键值对,这些键值对都是HTTP定义好的、有特殊含…...
随想录刷题笔记 —二叉树篇10 450删除二叉搜索树节点 669修剪二叉搜索树 108有序数组转换为二叉搜索树
450删除二叉搜索树节点 删除结点分为2种情况: 1.结点的孩子只有一个或没有,则直接用孩子或空替代 2.结点的孩子有两个,用左孩子替代,将左孩子的右孩子移到结点右子树的最左结点 解法一:递归 class Solution {publ…...
Docker基础篇(二)
docker run -d docker run -d 容器名或容器ID docker run -d 后台生成容器,并退出容器(除容器中在运行脚本) docker run -it 交互生成容器 docker run -d centos /bin/sh -c “while true; do echo zen; sleep 2;done” 查看容器中的进程…...
时序数据库TimescaleDB,实战部署全攻略
📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…...
Gson 库的使用
Gson 是由 Google 开发的一个流行的 Java 库,用于处理 JSON 数据的序列化和反序列化。它提供了简单易用的 API,使得在 Java 应用程序中操作 JSON 数据变得非常方便。 以下是 Gson 库的一些主要特点和用法 简单易用 Gson 提供了一个简单而直观的 API,使得在 Java 应用程序中…...
Java Swing游戏开发学习1
不使用游戏引擎,只使用Java SDK开发游戏的学习。 游戏原理 图片来自RyiSnow视频讲解 原理结合实际代码 public class GamePanel extends Jpanel implements Runnable {...run(){}// 详情看下图... }项目结构 运行效果 代码code 在我的下载里面可以找到&#x…...
Stable Diffusion 模型的概念、类型、下载、安装、使用
本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 大家好,我是水滴~~ 我们在《Stable Diffusion WebUI 界面介绍》 时,第一个就讲到了 Stable Diffusion 模型,那么这个模型是什么?该从哪儿下载&…...
Go 1.22 对 net/http 包的路由增强功能详解
目录 方法匹配(Method Matching) 通配符(Wildcards) 路径前缀匹配 优先规则 兼容性 API 变更 小结 参考资料 Go 1.22 版本对 net/http 包的路由功能进行了增强,引入了方法匹配(method matching&…...
【安卓基础3】Activity(一)
🏆作者简介:|康有为| ,大四在读,目前在小米安卓实习,毕业入职 🏆本文收录于 安卓学习大全,欢迎关注 🏆安卓学习资料推荐: 视频:b站搜动脑学院 视频链接 &…...
SpringBoot基于JWT的token做登录认证
背景 我们在基于Session做登录认证的时候,会有一些问题,因为Session存储到服务器端,然后通过客户端的Cookie进行匹配,如果正确,则通过认证,否则不通过认证。这在简单的系统中可以这么使用,并且…...
[ 2024春节 Flink打卡 ] -- Paimon
2024,游子未归乡。工作需要,flink coding。觉知此事要躬行,未休,特记 Flink 社区希望能够将 Flink 的 Streaming 实时计算能力和 Lakehouse 新架构优势进一步结合,推出新一代的 Streaming Lakehouse 技术,…...
计算机网络——14CDN
CDN 视频流化服务和CDN:上下文 视频流量:占据着互连网大部分的带宽 Netflix,YouTube:占据37%,16%的下行流量 挑战:规模性-如何服务~1B用户? 单个超级服务器无法提供服务(为什么&am…...
Vivado里SRIO IP核Basic模式配置详解:从链路宽度到Buffer深度,新手避坑指南
Vivado中SRIO IP核Basic模式配置全解析:从参数理解到实战避坑 第一次在Vivado中配置SRIO IP核时,面对密密麻麻的参数选项,大多数工程师都会感到无从下手。作为Xilinx FPGA中实现高速串行通信的关键IP,SRIO(Serial Rap…...
Halcon读取条形码和二维码
读取条形码1创建条形码句柄create_bar_code_model(: : GenOaramName,GenParamValue: BarCodeHandle)2设置条形码参数GenParamName 设置的参数element_size_min 条形码最小单位,黑条之间的最小间距barcode_width_min条形码的最小宽度persistence 设置条形码的查找精度…...
BiLSTM时间序列预测实战:用Python搞定股票价格预测(附完整代码)
BiLSTM金融时间序列预测:从理论到实战的Python完整指南 金融市场如同汹涌的海浪,价格波动背后隐藏着无数投资者的决策与情绪。对于量化分析师和算法交易者而言,准确预测这些波动意味着巨大的商业价值。传统的时间序列分析方法如ARIMA在面对非…...
Torch-Pruning支持神经辐射场(NERF):3D重建模型压缩终极指南
Torch-Pruning支持神经辐射场(NERF):3D重建模型压缩终极指南 【免费下载链接】Torch-Pruning [CVPR 2023] Towards Any Structural Pruning; LLMs / Diffusion / Transformers / YOLOv8 / CNNs 项目地址: https://gitcode.com/gh_mirrors/to/Torch-Pruning 神…...
如何使用Kubernetes Python Client实现安全策略:准入Webhook完整指南
如何使用Kubernetes Python Client实现安全策略:准入Webhook完整指南 【免费下载链接】python Official Python client library for kubernetes 项目地址: https://gitcode.com/gh_mirrors/python1/python Kubernetes Python Client是官方提供的Python客户端…...
Cadence启动文件背后的设计哲学:为什么.cdsinit总覆盖不了.cdsenv的设置?
Cadence启动文件背后的设计哲学:为什么.cdsinit总覆盖不了.cdsenv的设置? 当你在Cadence Virtuoso中反复调整波形显示参数,却发现每次重启后设置都被重置时,背后隐藏的是一套精妙的EDA工具配置体系。这个看似简单的"设置失效…...
OpenClaw技能市场探索:GLM-4.7-Flash加持的10个实用插件
OpenClaw技能市场探索:GLM-4.7-Flash加持的10个实用插件 1. 为什么需要关注OpenClaw技能市场? 当我第一次接触OpenClaw时,最让我惊喜的不是它的基础功能,而是它丰富的技能市场生态。作为一个长期使用各类自动化工具的技术爱好者…...
应对维普AIGC史诗级升级:2026降重急救包!5款工具基准测试 x 4大手改重构技巧
论文初稿快要交了,维普却突然搞了个大动作,把系统给升级了。说实话,这事真挺让人头疼的,有人前两天查还是绿的,以为稳了,结果升级完再一测,AI率直接飙红。 但别慌,也别怀疑自己是不…...
美图靠AI一年收入38亿,不靠免费大模型API,靠的是什么?
财报数据显示,美图2025年全年实现营业收入38.6亿元,同比大幅增长28.8%,整体营收规模再创新高,展现出核心业务的强劲增长韧性。不过公司常规账面净利润为7亿元,同比下降12.7%,看似利润下滑的背后,…...
攻防世界 misc题GFSJ1129-【您看我还有机会吗?】
1.工具:010editor、VMware(Ubuntu、binwalk)、在线 Brainfuck解密、CTF-Tools、ImageStrike、7zFM 2.解题: 方法一(最初的解法): 下载附件后,我们打开,发现有一张图片,点击后发现要密码,我发现没有任何密码的提示,怀疑是伪加密(由于篇幅较长,我后续会在写一篇…...
