Socket 编程 TCP
目录
1. TCP socket API 详解
1.1 socket
1.2 bind
1.3 listen
1.4 accept
1.5 read&&write
1.6 connect
1.7 recv
1.8 send
1.9 popen
1.10 fgets
2. EchoServer
3. 多线程远程命令执行
4. 引入线程池版本翻译
5. 验证TCP - windows作为client访问Linux
6. connect的断线重连
1. TCP socket API 详解
下面介绍程序中用到的socket API,这些函数都在sys/socket.h中。
1.1 socket
// main socket
NAMEsocket - create an endpoint for communicationSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);
// domain:域,表示要进行网络通信,AF_INET
// type:套接字类型,TCP就填SOCK_STREM(流式套接字),UDP就填SOCK_DGRAM(数据包套接字)
// protocol:设置为0,默认就是TCP Socket// 返回值
RETURN VALUEOn success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately.
// 跟UDP一样,成功就是新的文件描述符,失败就返回-1
1.2 bind
// man bind
NAMEbind - bind a name to a socketSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
// 填充当前服务器本地的socket信息,文件信息和网络信息关联起来。// 返回值
RETURN VALUEOn success, zero is returned. On error, -1 is returned, and errno is set appropriately.
// 如果成功了0被返回,否则-1被返回
1.3 listen
TCP的有连接和UDP的无连接
UDP叫面向数据报,无连接的,TCP叫面向字节流,有连接的,怎么证明UDP是无连接的呢?
只要我客户端一启动,随时就可以向服务器发消息,所以我们直接创建套接字之后,直接sendto就可以向服务器发消息了,没有所谓的连接,而TCP叫做面向连接的协议,即有连接,所以我们对应的TCP,要面向连接,如果我们的客户端(c)连接服务器(s),也叫cs模式,如果c向s发起对应的请求,就先的建立连接,连接建立成功才能通信,这就是TCP的特点,而客户点要连服务器,是不是要求这个服务器随时随地等待被连接。所以TCP是建立连接的,一定会存在协商的过程,所以tcp需要将socket设置为监听状态。
// man listen
NAMElisten - listen for connections on a socket// 意思就是再等别人随时随地来连接我SYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int listen(int sockfd, int backlog);
// sockfd:设置的文件描述符
// backlog:服务器所对应的操作系统中所对应的全连接的个数,不建议为0,也不能太长,8,4,14,32都可以,具体设置多大,按照自己的需求来做,backlog是积压的意思,就类似于排队,但是排队也不能排太长// 返回值
RETURN VALUEOn success, zero is returned. On error, -1 is returned, and errno is set appropriately.
// 成功了返回0,失败了-1被返回
1.4 accept
// man accept
NAMEaccept, accept4 - accept a connection on a socketSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);#define _GNU_SOURCE /* See feature_test_macros(7) */#include <sys/socket.h>int accept4(int sockfd, struct sockaddr *addr,socklen_t *addrlen, int flags);// 从指定的文件描述符当中获取新连接,获取新的客户端,当别人连接你的时候,第一件是就是要知道谁来连我,
// sockfd:套接字
// addr && addrlen:输出型参数,其实就相当于给我们传进来缓冲区,当我们再进行获取新连接,这个上面所对应的sockaddr的客户端的地址就会直接给我们返回。这两个参数就等同于recvfrom,recvfrom的后两个参数。// 返回值
RETURN VALUEOn success, these system calls return a nonnegative integer that is a file descriptor for the accepted socket. On error, -1 is returned, errno is set appropriately, and addrlen is left unchanged.
// 如果成功就返回非0,失败-1返回。没有人连接就会阻塞。
// 成功后,这些系统调用将返回一个非负整数,该整数是所接受套接字的文件描述符,
// 正真提供服务的是由accept的返回值来定的。而sockfd是专门用来获取新连接的。
1.5 read&&write
读和写我们用的是read和write,因为我们的accept返回的是一个文件描述符,而且TCP是面向字节流的,管道和文件也是面向字节流的,所以TCP套接字,在我们获得了新的文件描述符之后,TCP套接字往后的处理都跟我们之前学习文件跟管道一样,我们可以调用read和write这样的文件接口来直接对网络进行读和写。
UDP不敢用read和write,因为UDP是面向数据报的,报文类型上是不一样的,至于什么是面向数据报,什么是面向字节流,单纯在应用层上编写代码是感受不到的,到TCP和UDP的原理时才能感受的到。
void HandlerRequest(int sockfd) // TCP也是全双工{char inbuffer[4096];while(true){size_t n = ::read(sockfd,inbuffer,sizeof(inbuffer)-1);if(n > 0){LOG(LogLevel::INFO) << inbuffer;inbuffer[n] = 0;std::string echo_str = "server echo# ";echo_str += inbuffer;::write(sockfd,echo_str.c_str(),echo_str.size());}}}void Start(){_isrunning = true;while(_isrunning){// 不能直接读数据// 1. 获取新连接struct sockaddr_in peer;socklen_t peerlen;int sockfd = ::accept(_listensockfd,CONV(&peer),&peerlen);if(sockfd < 0){LOG(LogLevel::WARNING) << "accept error: " << strerror(errno);continue;// 失败了不是报错,而是回头重新来}// 获取连接成功了LOG(LogLevel::INFO) << "accept success,sockfd id : " << sockfd;// version-0HandlerRequest(sockfd);}_isrunning = false;}
1.6 connect
// man connect
NAMEconnect - initiate a connection on a socketSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
// sockfd:客户端所创建的套接字
// addr && addrlen:访问目标服务器所对应的IP地址和端口号,// 返回值
RETURN VALUEIf the connection or binding succeeds, zero is returned. On error, -1 is returned, and errno is set appropri‐ately.
// 创建套接字成功,返回值就是0,否则就是-1.
1.7 recv
// man recv
NAMErecv, recvfrom, recvmsg - receive a message from a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);
// 从指定的文件描述符读取数据到buffer,长度是len,flage就是读取的标志位,默认设置为0就可以了,因为在我们当前的代码中,设置为0就表示的是阻塞的,他比read就多了一个flags,这是专门在套接字当中为我们处理IO接口,
1.8 send
// man send
NAMEsend, sendto, sendmsg - send a message on a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);
// 把特定缓冲区指定长度通过该文件描述符发出去,他也多了一个flags参数。
不管是read、write、recv还是end,他们的返回值的意思都是一样的,所以可以平滑过渡。
1.9 popen
// man popen
#include <stdio.h>
NAMEpopen, pclose - pipe stream to or from a processSYNOPSIS#include <stdio.h>FILE *popen(const char *command, const char *type);int pclose(FILE *stream);
// 它的底层其实就是帮我们做了这几件事情
/*
1. 执行 Shell 命令
启动一个新的子进程,运行指定的命令行程序(如 ls, grep, python 等)。
2. 建立单向管道
根据模式(读或写),创建一个管道:
读模式("r"):从子进程的输出(如 stdout)读取数据。
写模式("w"):向子进程的输入(如 stdin)写入数据。
3. 返回文件流指针
返回一个 FILE* 指针,可通过标准文件操作函数(如 fread, fgets, fprintf)与子进程交互。
*/
// 1. pipe
// 2. fork + dup2(pipe[1],1) + exec*,执行结果给父进程,pipe[0]
// 3. return
// 返回值是FILE*的,其实就是把管道封装起来,封装成一个文件了。// 返回值
RETURN VALUEpopen(): on success, returns a pointer to an open stream that can be used to read or write to the pipe; if the fork(2) or pipe(2) calls fail, or if the function cannot allocate memory, NULL is returned.// 成功的话就返回一个文件流,失败返回空pclose(): on success, returns the exit status of the command; if wait4(2) returns an error, or some other error is detected, -1 is returned.Both functions set errno to an appropriate value in the case of an error.// 一个线程执行fork就相当于当前进程创建子进程。
1.10 fgets
// man fgets
NAMEfgetc, fgets, getc, getchar, ungetc - input of characters and strings
SYNOPSIS#include <stdio.h>char *fgets(char *s, int size, FILE *stream);
// 返回值
RETURN VALUEfgets() returns s on success, and NULL on error or when end of file occurs while no characters have been read.// 读取失败返回NULL
2. EchoServer
Linux: This repository is specifically designed to store Linux code - Gitee.comhttps://gitee.com/Axurea/linux/tree/master/2025_05_26_EchoServer
3. 多线程远程命令执行
Linux: This repository is specifically designed to store Linux code - Gitee.comhttps://gitee.com/Axurea/linux/tree/master/2025_05_28_CommandServerTcp
4. 引入线程池版本翻译
- 上篇UDP部分写过类似的设计方案。
- 后面我们还会涉及http相关内容,到时候在引入线程池会更方便,也很合理。
5. 验证TCP - windows作为client访问Linux
Linux: This repository is specifically designed to store Linux code - Gitee.comhttps://gitee.com/Axurea/linux/tree/master/2025_05_28_Tcp_WindowsClient&&LinxuServer
注意:一定要开放云服务器对应的端口号,在你的阿里云或者腾讯云、华为云的网站后台中开放。
我们可以发现tcp client(windows)和tcp server(Linux)可以通信。
WinSock2.h是Windows Sockets API(应用程序接口)的头文件,用于在Windows平台上进行网络编程。它包含了Windows Sockets 2(WinSock2)所需的数据类型、函数声明和结构定义,使得开发者能够创建和使用套接字(sockets)进行网络通信。
在编写使用Winsock2的程序时,需要在源文件中包含WinSock2.h头文件。这样,编译器就能够识别并理解Winsock2中定义的数据类型和函数,从而能够正确的编译和链接网络相关的代码。
此外,与WinSock2.h头文件相对应的是ws2_32.lib库文件。在链接阶段,需要将这个库文件链接到程序中,以确保运行时能够找到并调用Winsock2 API中实现的函数。
在WinSock2.h中定义了一些重要的数据类型和函数,如:
WSADATA:保存初始化Winsock库时返回的信息。
SOCKET:表示一个套接字描述符,用于在网络中唯一标识一个套接字。
sockaddr_in:IPv4地址结构体,用于存储IP地址和端口号等信息。
socket():创建一个套接字。
bind():将套接字与本地地址绑定。
listen():将套接字设置为监听模式,等待客户端的连接请求。
accept():接受客户端的连接请求,并返回一个新的套接字描述符,用于与客户端
进行通信。
WSAStartup函数是Windows Sockets API的初始化函数,它用于初始化Winsock库。该函数在应用程序或DLL调用任何Windows套接字函数之前必须首先执行,它扮演着初始化的角色。
以下是WSAStartup函数的一些关键的:
它接受两个参数:wVersionRequested和IpWSAData。wVersionRequested用于指定所请求的Winsock版本,通常使用MAKEWORD(major,minor)宏,其中major和minor分别标识请求的主版本号和次版本号。IpWSAData是一个指向WSAData结构的指针用于接收初始化信息。
如果函数调用成功,它会返回0:否则,返回错误代码。
WSAStartup函数的主要作用是向操作系统说明我们将使用哪个版本的Winsock库,从而使得该库文件能与当前的操作系统协同工作。成功调用该函数后,Winsock库的状态会被初始化,应用程序就可以使用Winsock提供的一系列套接字服务,如地址家族识别、地址转换、名字查询和连接控制等。这些服务使得应用程序可以与底层的网络协议栈进行交互,实现网络通信。
在调用WSAStartup函数后,如果应用程序完成了对请求的Socket库的使用,应调用
WSAStartup函数后,如果应用程序完成了对请求的Socket库的使用,应调用WSACleanup
函数来解除与Socket库的绑定并释放所占用的系统资源。
6. connect的断线重连
客户端会面临服务器崩溃的情况,我们可以试着写一个客户端重连的代码,模拟并理解一些客户端行为,比如游戏客户端等。
采用状态机,实现一个简单的tcp client可以实现重连的效果。
Linux: This repository is specifically designed to store Linux code - Gitee.comhttps://gitee.com/Axurea/linux/tree/master/2025_05_28_TcpClientConnect
相关文章:

Socket 编程 TCP
目录 1. TCP socket API 详解 1.1 socket 1.2 bind 1.3 listen 1.4 accept 1.5 read&&write 1.6 connect 1.7 recv 1.8 send 1.9 popen 1.10 fgets 2. EchoServer 3. 多线程远程命令执行 4. 引入线程池版本翻译 5. 验证TCP - windows作为client访问Linu…...
Redis-6.2.9 Sentinel 哨兵配置
目录 1 操作系统信息和redis软件版本 2 集群架构图 3 部署redis主从 4 sentinel 配置文件 5 运维管理 6 go编写应用业务测试 哨兵核心功能:能够后台监控redis主机是否故障,如果故障了根据投票自动将从库转换为主库 1 操作系统信息和redis软件版本 rootu24-re…...

基于TMC5160堵转检测技术的夹紧力控制系统设计与实现
点击下面图片带您领略全新的嵌入式学习路线 🔥爆款热榜 90万阅读 1.6万收藏 一、技术背景与系统原理 在工业自动化领域,夹紧力控制是精密装配、机床夹具等场景的核心需求。传统方案多采用压力传感器伺服电机的闭环控制方式,但存在系统复杂…...
从零开始搞个简易分布式部署环境
从零开始,意味着连个服务器都没有,所以第一步,随便上哪个顺眼的云厂家去租个便宜大碗的服务器(不要window系统的就行),说大碗也不太对,主要是这碗能在手里用得久,这个就自己扒拉去了…...

XCTF-web-fileclude
解析如下 <?php include("flag.php"); // 包含敏感文件(通常包含CTF挑战的flag) highlight_file(__FILE__); // 高亮显示当前PHP文件源代码(方便查看代码逻辑)if(isset($_GET["file1"]…...

OpenShift AI - 启用过时版本的 Notebook 镜像
《OpenShift / RHEL / DevSecOps 汇总目录》 说明:本文已经在 OpenShift 4.18 OpenShift AI 2.19 的环境中验证 文章目录 查看可用 Notebook 镜像控制台查看命令行查看 Notebook 镜像、Image Stream 和 Image Registry Repository 对应关系启用老版本的 Notebook 镜…...

Redis 缓存穿透、缓存击穿、缓存雪崩详解与解决方案
在分布式系统中,Redis 凭借高性能和高并发处理能力,成为常用的缓存组件。然而,在实际应用中,缓存穿透、缓存击穿、缓存雪崩这三大问题会严重影响系统的性能与稳定性。本文将详细解析这三个问题的成因,并提供对应的解决…...
sass高阶应用
Sass(尤其是 SCSS 语法)除了基础功能外,还提供了许多高级特性,可以实现更灵活、可维护的样式系统。以下是 Sass 的 高级语法和应用技巧,适合中大型项目或组件库开发。 文章目录 一、控制指令(Control Directives)1. `@if / @else`2. `@for` 循环3. `@each` 遍历列表/Map…...
docker docker-ce docker.io
Ubuntu安装 更新软件包列表 首先确保软件包列表是最新的: sudo apt-get update 使用正确的卸载命令 替换 docker-engine 为 docker-ce 或 docker.io: sudo apt-get remove docker docker-ce docker.io containerd runc 检查已安装的 Do…...

DQN和DDQN(进阶版)
来源: *《第五章 深度强化学习 Q网络》.ppt --周炜星、谢文杰 一、前言 Q表格、Q网络与策略函数 Q表格是有限的离散的,而神经网络可以是无限的。 对于动作有限的智能体来说,使用Q网络获得当下状态的对于每个动作的 状态-动作值 。那么 a…...

【组件】翻牌器效果
目录 效果组件代码背景素材 效果 组件代码 <template><divclass"card-flop":style"{height: typeof height number ? ${height}px : height,--box-width: typeof boxWidth number ? ${boxWidth}px : boxWidth,--box-height: typeof boxHeight nu…...

CentOS 7 环境中部署 LNMP(Linux + Nginx + MySQL 5.7 + PHP)
在 CentOS 7 环境中部署 LNMP(Linux Nginx MySQL 5.7 PHP) 环境的详细步骤如下。此方案确保各组件版本兼容,并提供完整的配置验证流程。 1. 更新系统 sudo yum update -y 2. 安装 MySQL 5.7 2.1 添加 MySQL 官方 YUM 仓库 由于MySQL并不…...

NX811NX816美光颗粒固态NX840NX845
NX811NX816美光颗粒固态NX840NX845 美光NX系列固态硬盘颗粒深度解析:技术、性能与市场全景透视 一、技术架构与核心特性解析 1. NX811/NX816:入门级市场的平衡之选 技术定位:基于176层TLC(Triple-Level Cell)3D NAN…...

捋捋wireshark
本猿搬砖时会用到wireshark分析pcap包,但频率不高,记过一些笔记,今天捋捋,希望能给初学者节省一点时间。 wireshark是个网络封包分析软件(network packet analyzer),可以用来抓流量包ÿ…...

c++学习之---模版
目录 一、函数模板: 1、基本定义格式: 2、模版函数的优先匹配原则: 二、类模板: 1、基本定义格式: 2、类模版的优先匹配原则(有坑哦): 3、缺省值的设置: 4、ty…...
MyBatis-Flex 全面指南:下一代轻量级持久层框架实战入门
🚀 MyBatis-Flex 全面指南:下一代轻量级持久层框架实战入门 本文将带你全面了解 MyBatis-Flex 的特性、常见用法、最佳实践,帮助你高效构建更简洁、更灵活的 Java 持久层代码。 🧩 什么是 MyBatis-Flex? MyBatis-Flex…...

第十六章 EMQX黑名单与连接抖动检测
系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具的安装与使用 …...
WebSphere(WAS)
WebSphere (WebSphere Application Server)为 SOA 环境提供软件,以实现动态的、互联的业务流程,为所有业务情形提供高度有效的应用程序基础架构。WebSphere 是 IBM 的应用程序和集成软件平台,包含所有必要的中间件基础…...
新编辑器编写指南--给自己的备忘
欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持&#x…...
xPSR
在 ARM Cortex-M3 中,xPSR(组合程序状态寄存器) 是核心的状态控制寄存器,由三个子状态寄存器合并而成,用于记录处理器的运算状态、中断状态和执行环境。以下是其深度解析: 🔍 一、xPSR …...

鸿蒙网络数据传输案例实战
一、案例效果截图 二、案例运用到的知识点 核心知识点 网络连接管理:connection模块HTTP数据请求:http模块RPC数据请求:rcp模块文件管理能力:fileIo模块、fileUri模块 其他知识点 ArkTS 语言基础V2版状态管理:Comp…...

【JavaEE】-- 网络原理
文章目录 1. 网络发展史1.1 广域网1.2 局域网 2. 网络通信基础2.1 IP地址2.2 端口号2.3 认识协议2.4 五元组2.5 协议分层2.5.1 分层的作用2.5.2 OSI七层模型(教科书)2.5.3 TCP/IP五层(或四层)模型(工业中常用ÿ…...

1.RV1126-OPENCV 交叉编译
一.下载opencv-3.4.16.zip到自己想装的目录下 二.解压并且打开 opencv 目录 先用 unzip opencv-3.4.16.zip 来解压 opencv 的压缩包,并且进入 opencv 目录(cd opencv-3.4.16) 三. 修改 opencv 的 cmake 脚本的内容 先 cd platforms/linux 然后修改 arm-gnueabi.to…...

PySide6 GUI 学习笔记——常用类及控件使用方法(标签控件QLabel)
文章目录 标签控件QLabel及其应用举例标签控件QLabel的常用方法及信号应用举例Python 代码示例1Python 代码示例2 小结 标签控件QLabel及其应用举例 QLabel 是 PySide6.QtWidgets 模块中的一个控件,用于在界面上显示文本或图像。它常用于作为标签、提示信息或图片展…...

CSS (mask)实现服装动态换色:创意与技术的完美融合
在网页开发中,我们常常会遇到需要对图片元素进行个性化处理的需求,比如改变图片中特定部分的颜色。今天,我们就来探讨一种通过 CSS 和 JavaScript 结合,实现服装动态换色的有趣方法。 一、代码整体结构分析 上述代码构建了一个完…...

基于51单片机的音乐盒汽车喇叭调音量proteus仿真
地址: https://pan.baidu.com/s/1l3CSSMi4uMV5-XLefnKoSg 提取码:1234 仿真图: 芯片/模块的特点: AT89C52/AT89C51简介: AT89C51 是一款常用的 8 位单片机,由 Atmel 公司(现已被 Microchip 收…...

彻底理解Spring三级缓存机制
文章目录 前言一、Spring解决循环依赖时,为什么要使用三级缓存? 前言 Spring解决循环依赖的手段,是通过三级缓存: singletonObjects:存放所有生命周期完整的单例对象。(一级缓存)earlySingleto…...
MacOs 安装局域网 gitlab 记录
1、安装git brew install git > Downloading https://homebrew.bintray.com/bottles/git-2.7.0.el_capitan.bottle ######################################################################## 100.0% > Pouring git-2.7.0.el_capitan.bottle.tar.gz > Caveats The O…...
Flutter 与 Android 原生布局组件对照表(完整版)
本对照表用于帮助 Android 开发者快速理解 Flutter 中的布局组件与原生布局的关系。 📘 Flutter ↔ Android 布局组件对照表 Flutter WidgetAndroid View/Layout说明ContainerFrameLayout / View通用容器,可设置背景、边距、对齐等RowLinearLayout (hor…...

【产品经理从0到1】自媒体端产品设计
后台的定义 “后台” 与“前台”都是相对独立的平台,前台是服务于互联网用户的平台 ,后台主要是支撑前台页面内容、数据及对前台业务情况的统计分析的系统; 后台与前台的区别 第1:使用用户不同 前台用户:互联网用户…...