TCP开发
TCP客户端编程开发
任何的网络编程套接字开发的两种工作模式:TCP网络、UDP网络。
TCP和UDP的介绍
TCP:连接式网络通信,长连接通信或流式通信。TCP的通信一般稳定、可靠,但传输速度往往没有UDP快。其中有这样一个概念----心跳时间,用以保持长链接。而它可靠的原因就是他的三次握手(链接)和四次挥手(断开连接)。类似于打电话。
UDP:报式网络通信,短链接通信方法,或者说无链接。相较于TCP来说,安全可靠性低,但速度超高。类似于发短信。
两者如何选择,取决于在编程中输入的参数。
TCP的三次握手和四次挥手
- 三次握手
第一次握手:客户端向服务器发送一个 SYN包,其中包含客户端随机生成的初始序列号,记为 seq=x。这个包的作用是向服务器表明客户端想要建立连接,并告知服务器自己的初始序列号。此时客户端进入 SYN_SENT 状态。
第二次握手:服务器接收到客户端的 SYN 包后,会向客户端发送一个 SYN+ACK 包。该包中,确认号为客户端的序列号加 1,即 ack=x+1,表示服务器已经收到了客户端的 SYN 包,并且准备好接收客户端的数据。同时,服务器也会随机生成一个自己的初始序列号 seq=y。此时服务器进入 SYN_RCVD 状态。
第三次握手:客户端收到服务器的 SYN+ACK 包后,会向服务器发送一个 ACK 包。该包的确认号为服务器的序列号加 1,即 ack=y+1,序列号为客户端在第一次握手中发送的序列号加 1,即 seq=x+1。服务器收到这个 ACK 包后,连接建立成功,双方进入 ESTABLISHED 状态,开始进行数据传输。
- 四次挥手
第一次挥手:主动关闭方(通常是客户端)发送一个 FIN(Finish)包,其中包含主动关闭方的序列号 seq=u,表示主动关闭方已经没有数据要发送了,请求关闭连接。此时主动关闭方进入 FIN_WAIT_1 状态。
第二次挥手:被动关闭方收到 FIN 包后,会发送一个 ACK 包,确认号为主动关闭方的序列号加 1,即 ack=u+1,序列号为被动关闭方自己的序列号 seq=v。此时被动关闭方进入 CLOSE_WAIT 状态,而主动关闭方收到 ACK 包后进入 FIN_WAIT_2 状态。
第三次挥手:被动关闭方在完成数据处理后,也会发送一个 FIN 包,其中序列号为 seq=w(如果在收到 FIN 包后没有新的数据发送,w=v+1),确认号仍然为 ack=u+1。此时被动关闭方进入 LAST_ACK 状态。
第四次挥手:主动关闭方收到被动关闭方的 FIN 包后,会发送一个 ACK 包进行确认,确认号为 ack=w+1,序列号为 u+1。主动关闭方发送完这个 ACK 包后进入 TIME_WAIT 状态,等待一段时间(通常为 2 倍的 MSL,最长报文段寿命)后,如果没有收到被动关闭方的重传请求,则认为连接已经成功关闭,进入 CLOSED 状态。被动关闭方收到 ACK 包后,也会进入 CLOSED 状态。
TCP 的三次握手和四次挥手机制,可以理解为不断加包的过程,保证了网络中数据传输的可靠性和稳定性,使得客户端和服务器之间能够准确地建立连接和关闭连接。
Linux下TCP客户端开发接口函数:
socket();//创建套接字
connect(); //链接xxx服务器
write();//通过套接字发送数据给服务器
read(); //通过套接字读取服务器发来的消息
close(); //关闭链接的服务器
socket();
函数功能:创建一个套接字
函数头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型: int socket(int domain, int type, int protocol);
函数参数:
domain:AF_INET : IPV4 | AF_INET6: IPV6
type: 你创建的套接字的类型-> TCP/UDP
SOCK_STREAM->流式套接字 TCP
SOCK_DGRAM->报式套接字 UDP
protocol: 如果不是原始套接字 这个固定填 0
函数返回值:成功返回一个文件描述符,失败返回负数。基本上不可能失败,除非当前的进程打开的文件超出上限!
Call back open函数,这就好比用open函数打开一个普通文件,open返回的是这个文件的描述符,而socket 返回的是套接字对应的描述符。你之后对这个返回的描述符进行操作,就相当于在操作这个套接字,比如发送和接收数据。
connect();
函数功能:利用套接字链接其他的服务器(可以是内网服务器/也可以公网服务器
函数头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型: int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函数参数:
- sockfd:链接服务器的套接字
- addr:如果使用的是IPV4的地址,建议使用struct sockaddr_in 结构体充当第二个参数。第二个参数主要作用是提供连接服务器:链接类型(IPV4/IPV6) 、端口号、IP地址。
PS:所有网络编程的存储方式为大端!所以在填入端口号时,需要利用htons将原本的小端格式转换为大端格式。例如,htons(55555)==985,小端格式存储的55555,转化为大端格式就是985。
而在填入地址时,也要注意地址本质是一个uint32_t类型的数字。所以需要快速直接转换整型 IP 变成大端 可以借助iner_addr函数。例如,整型的大端 IP = inet_addr(字符串 IP)。
函数返回值: 该函数会阻塞,直到出现以下两种情况:
链接服务器通过!返回0 | 链接失败/超时,返回负数
TCP客户端获取高德天气数据
#include "sys/types.h"
#include "stdlib.h"
#include "unistd.h"
#include "string.h"
#include "sys/socket.h"
#include "stdio.h"
#include <pthread.h>
#include <arpa/inet.h>
#include "netinet/in.h"
#define POST "GET https://restapi.amap.com/v3/weather/weatherInfo?city=410102&key=15dfb2a0ae03b142a72afbc9cbbd47e4\r\n"
pthread_t pd;
int skd;
int main(){//1. 创建套接字skd = socket(AF_INET, SOCK_STREAM,0);if(skd < 0){perror("socket");exit(0);}printf("套接字创建成功 skd==%d\r\n", skd);//2.创建sock_addrstruct sockaddr_in server_addr = {0};server_addr.sin_family = AF_INET;server_addr.sin_port = htons(80);//一般是8080或80,使用时可以试一下是哪个server_addr.sin_addr.s_addr = inet_addr("106.11.226.133");//高德开发的IP地址printf("sockaddr: %d\n",server_addr.sin_addr.s_addr);//3. 连接服务器int ret = connect(skd, (struct sockaddr*)&server_addr, sizeof(server_addr));if ((ret<0)){perror("connect");exit(0);}printf("连接服务器成功\r\n");char send_buf[2048] = {0};printf("POST==%s\r\n",send_buf);usleep(100*100);write(skd,POST,103);usleep(100*100);read(skd,send_buf,sizeof(send_buf));printf("send_buf==%s\n",send_buf);return 0;
}
实验现象:

TCP服务器编程开发
服务器
服务器就是有被别人连接能力的电脑。服务器分内网和公网两种:
内网服务器:若服务器程序使用的是电脑从路由器或交换机获取的 IP 地址,那么该程序仅能被处于同一网络的主机访问。例如,在 Ubuntu 系统中,服务器所在电脑的 IP 地址为 192.168.222.128 ,只有连接到同一路由器、网关或交换机的主机才能连接此服务器。使用手机热点上网的设备则无法连接该服务器。
公网服务器:要搭建公网服务器,需向联通、移动、电信等运营商申请开通静态 IP 上网服务,与运营商协商使宽带 IP 固定,并获取一定的对外访问权限。理论上,这样搭建的服务器可被全国范围内的用户通过网络连接。但实际上,运营商通常不会支持此类操作。较为可行的做法是将服务器程序部署到阿里云、百度云、腾讯云等云服务器上,如此一来,全球任何位置的用户都能访问该服务器程序。
服务器程序的开发流程:
- 需要创建一个TCP的套接字----socket()
- 绑定服务器的属性(IP地址、端口号)----bind()
- 监听->监测/允许链接的最大数----listen()
- 接收客户端的链接----accept()
- 与客户端通信----read()/write()
重点是,就服务器而言,必须要有固定的IP地址和端口号!
在多网卡的情况下,绑定不同的IP地址相当于使用不同网卡上网。
Linux下TCP服务器开发接口函数:
bind()
函数原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数功能:绑定给服务器(套接字)固定的IP地址和端口号
函数头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
函数参数:
- sockfd:绑定给服务器的套接字
- addr:绑定给服务器的IPV4/IPV6、IP地址、端口号等属性。建议使用struct sockaddr_in类型
- addrlen:上个参数的长度
函数返回值:成功返回0 | 失败返回负数
listen()
函数原型:int listen(int sockfd, int backlog);
函数功能:监听服务器,设置服务器的最大连接数
函数头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
函数参数:
- sockfd:设置的套接字(服务器)
- backlog:允许链接/要监听的数量
函数返回值:成功返回0 | 失败返回负数
accept()
函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数功能:接收一个客户的链接。如果调用该函数的时候没有客户链接,则会阻塞,等到有客户链接的时候,便立即返回,达到同步的效果。
函数参数:
- sockfd:服务器的套接字
- addr:用来存放客户返回的属性
- addr_len:一般创建一个socklen_t len;len=sizeof(struct sockaddr_in);并把&len传入其中
函数返回值:返回值是客户的套接字。后续的与该用户通信需要用到这个套接字。
TCP服务器通信测试
#include "sys/types.h"
#include "stdlib.h"
#include "unistd.h"
#include "string.h"
#include "sys/socket.h"
#include "stdio.h"
#include <pthread.h>
#include <arpa/inet.h>
#include "netinet/in.h"
void * Client_read_data_output(void * arg);
int ckd[64]={0};
int ckdcount = 0;
int main(){//1. 创建套接字int skd = socket(AF_INET, SOCK_STREAM, 0);if(skd < 0){perror("socket");exit(0);}printf("套接字创建成功,skd==%d\r\n", skd);//2. 定义sockaddr_in 结构体,并填充所需参数struct sockaddr_in server_addr = {0};server_addr.sin_family = AF_INET;server_addr.sin_port = htons(11112);server_addr.sin_addr.s_addr = inet_addr("172.20.10.2");//3. 给当前套接字绑定一个IP地址和端口号int tmp = bind(skd, (struct sockaddr *)&server_addr,sizeof(server_addr));if(tmp<0){perror("bind");exit(0);}//4. 监听tmp = listen(skd,64);//最大允许64个连接pthread_t pd;//5.轮询地接受客户连接struct sockaddr_in Clien_addr;socklen_t len = sizeof(Clien_addr);while(1){ckd[ckdcount++] = accept(skd,(struct sockaddr *)&Clien_addr,&len);printf("现在有%d个连接到了我的服务器\r\n",ckdcount);pthread_create(&pd, NULL, Client_read_data_output, &ckd[ckdcount-1]);}return 0;
}
void * Client_read_data_output(void * arg)
{int ckd = *((int *)arg);//套接字传入线程char buff[1024]={0};int len = 0;while(1){memset(buff, 0, sizeof(buff));len = read(ckd, buff, sizeof(buff));if(len==0){printf("客户%d离线了", ckd);close(ckd);pthread_exit(NULL);}printf("来自客户%d的消息:%s\n",ckd,buff);}
}
实验现象:

相关文章:
TCP开发
TCP客户端编程开发 任何的网络编程套接字开发的两种工作模式:TCP网络、UDP网络。 TCP和UDP的介绍 TCP:连接式网络通信,长连接通信或流式通信。TCP的通信一般稳定、可靠,但传输速度往往没有UDP快。其中有这样一个概念----心跳时…...
【核心算法篇十二】《深入解剖DeepSeek多任务学习:共享表示层的24个设计细节与实战密码 》
引言:为什么你的模型总在"精神分裂"? 想象你训练了一个AI实习生: 早上做文本分类时准确率90%下午做实体识别却把"苹果"都识别成水果公司晚上做情感分析突然开始输出乱码这就是典型的任务冲突灾难——模型像被不同任务"五马分尸"。DeepSeek通…...
Java 基于SpringBoot+Vue 的旅游网站信息化管理系统设计与实现
Java 基于SpringBootVue 的旅游网站信息化管理系统设计与实现 博主介绍:✌程序员徐师兄、8年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战*✌ 🍅文末获取源码联系ἴ…...
构建简单RAG代码实现
步骤1:文档准备与切割 假设我们有一个关于机器学习的PDF文档需要处理。 示例代码: Python 深色版本 from llama_index import SimpleDirectoryReader # 加载文档 documents SimpleDirectoryReader(./data).load_data() 说明: 使用Simple…...
kubeadm拉起的k8s集群证书过期的做法集群已奔溃也可以解决
kubeadm拉起的k8s集群证书过期的做法 这个是很久之前遇到的了,今天有空(心血来潮)就都回忆回忆写在这里为爱发光,部分内容来自arch先生(死党)的帮助。有时候有很多部门提了建k8s的需求,有些是临…...
Ubuntu:20.04更新cmake到更高版本
从输出信息可以看出,您当前的系统中已经安装了 cmake,但版本是 3.16.3,而您的项目需要 CMake 3.18 或更高版本。默认情况下,Ubuntu 20.04 的官方软件仓库中提供的 CMake 版本较低(如 3.16.3),因…...
php 系统命令执行及绕过
文章目录 php的基础概念php的基础语法1. PHP 基本语法结构2. PHP 变量3.输出数据4.数组5.超全局变量6.文件操作 php的命令执行可以执行命令的函数命令执行绕过利用代码中命令(如ls)执行命令替换过滤过滤特定字符串神技:利用base64编码解码的绕…...
【Java】泛型与集合篇 —— Set 接口
目录 Set 接口及实现类HashSet 类特点内部实现构造方法LinkedHashSet 类基本概念特点构造方法常用方法适用场景用 Set 对象实现集合运算TreeSet 类特性构造方法常用方法注意事项对象顺序自然排序定制排序注意事项Set 接口及实现类 HashSet 类 HashSet 是 Java 集合框架中 Set…...
基于YOLOv8的人脸识别系统
文章目录 一.前言 二.原理阐述 三.源代码 四.代码改进 五.流程概述 一.前言 原开源项目是对于某时段校园门口学生出入的视频,使用YOLOv8目标检测算法以及yolov8l-face模型将目标换算成只检测人脸, 通过该模型中的track技术实现检测出的人脸进行自动跟踪, 通过跟踪到的…...
HBuilderX中,VUE生成随机数字,vue调用随机数函数
Vue 中可以使用JavaScript的Math.random() 函数生成随机数,它会返回 0 到 1 之间的浮点数, 如果需要0到1000之前的随机数,可以对生成的随机数乘以1000,再用js的向下取整函数Math.floor() 。 let randNum Math.random(); // 生成…...
论文笔记-WSDM2024-LLMRec
论文笔记-WSDM2024-LLMRec: Large Language Models with Graph Augmentation for Recommendation LLMRec: 基于图增强的大模型推荐摘要1.引言2.前言2.1使用图嵌入推荐2.2使用辅助信息推荐2.3使用数据增强推荐 3.方法3.1LLM作为隐式反馈增强器3.2基于LLM的辅助信息增强3.2.1用户…...
计算四个锚点TOA定位中GDOP的详细步骤和MATLAB例程
该MATLAB代码演示了在三维空间中,使用四个锚点的TOA(到达时间)定位技术计算几何精度衰减因子(GDOP)的过程。如需帮助,或有导航、定位滤波相关的代码定制需求,请联系作者 文章目录 DOP计算原理MATLAB例程运行结果示例关键点说明扩展方向另有文章: 多锚点Wi-Fi定位和基站…...
Lookup Join显著增强,Paimon1.0版本如何做的?
Hi,大家好,我们又满血复活了。 2025年开年更新频率不快,一方面是大模型如火如荼,也一直在补相关知识;另外一方面,新的一年里身体健康被我摆到了第一位,不会像前几年那么卷了。 后续我们的更新会…...
【Golang学习之旅】如何在Go语言中使用Redis实现分布式锁,并解决锁过期导致的并发问题?
文章目录 前言1. 分布式锁的基本原理1.1 锁过期导致并发问题的解决: 2. Go实现分布式锁3. 代码实现分布式锁3.1 安装Go-Redis包3.2 创建分布式锁工具函数3.3 代码解析 4. 如何避免锁过期导致的并发问题4.1 延长锁的有效期4.2 利用Redis的WATCH命令(乐观锁…...
Vue前端开发-Vant组件之Button组件
Vant 有丰富的UI组件,而基础组件是全部组件的核心,基础组件中将常用的元素做了二次的开发,封装成Vant格式组件,如按钮、图片和布局等,这些封装后的Vant组件,提供了更多面向实际应用的属性和事件,…...
DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)
前言 在当今数字化时代,AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型,凭借其出色的性能和开源免费的优势,成为许多开发者的首选。今天,就让我们一起探索如何将DeepSeek接入PyCharm,实现高效、智…...
【Linux网络编程】应用层协议HTTP(请求方法,状态码,重定向,cookie,session)
🎁个人主页:我们的五年 🔍系列专栏:Linux网络编程 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 Linux网络编程笔记: https://blog.cs…...
健康养生:从生活细节开启活力之旅
在忙碌的现代生活里,健康养生不再是一个抽象概念,而是关乎生活质量的关键。其实,只要掌握日常养生要点,就能轻松开启活力满满的健康生活。 饮食是健康的基石。每日饮食需遵循 “彩虹原则”,摄入多种颜色食物。早餐时&…...
DeepSeek + Mermaid编辑器——常规绘图
下面这张图出自:由清华大学出品的 《DeepSeek:从入门到精通》。 作为纯文本生成模型,DeepSeek虽不具备多媒体内容生成接口,但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作,最终…...
DevOps自动化部署详解:从理念到实践
在软件开发日益快速迭代的今天,如何以高效、稳定且可重复的方式将代码变更从开发环境自动部署到生产环境成为企业竞争的重要因素。DevOps 正是在这一背景下应运而生,它打破开发、测试、运维之间的壁垒,通过自动化工具和流程,实现持…...
【拥抱AI】GPT Researcher的诞生
一、GPT Researcher 研究过程总结 GPT Researcher 是一个开源的自主智能体,旨在通过利用人工智能技术实现高效、全面且客观的在线研究。它通过一系列创新的设计和优化,解决了传统研究工具(如 AutoGPT)中存在的问题,如…...
Redis7——基础篇(三)
前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。 基础篇: Redis(一)Redis(二) 接上期内容:上期完成了Redis的基本…...
ES12 weakRefs的用法和使用场景
ES12 (ECMAScript 2021) 特性总结:WeakRef 1. WeakRef 概述 描述 WeakRef 是 ES12 引入的一个新特性,用于创建对对象的弱引用。弱引用不会阻止垃圾回收器回收对象,即使该对象仍然被弱引用持有。WeakRef 通常与 FinalizationRegistry 结合使…...
【Elasticsearch】搜索时分片路由
Elasticsearch 的Search Shard Routing(搜索分片路由)是一个核心机制,用于在分布式环境中高效地分发和执行搜索请求,确保查询能够快速、准确地返回结果,同时充分利用集群资源并保持系统的高可用性。以下是结合上述内容…...
MySQL登录问题总结
不管何种数据库,使用的第一步都是先登录。 MySQL命令行登录语句:mysql -u username -P port -p -D database_name 登录MySQL的报错一般从报错信息都能得到反馈,常见报错原因分析如下,实例中的以test用户为例,登录环境为…...
一些耳朵起茧子的名词解释
1 web应用 1.1 web应用的概念 Web应用(Web Application) 是一种通过浏览器访问的软件程序,它运行在服务器上,用户通过网络(如互联网或内网)与它进行交互。与传统网站(主要提供静态内容&#x…...
Redis 持久化:从零到掌握
Redis 作为一款广泛使用的内存数据库,虽然核心功能是基于内存提供高性能的数据存取,但在实际应用中,数据的持久化是不可忽视的。毕竟,内存中的数据一旦出现故障或重启,就会面临数据丢失的风险。因此,Redis …...
Mybatis MyBatis框架的缓存 一级缓存
1. 缓存的概念 缓存的概念 在内存中临时存储数据,速度快,可以减少数据库的访问次数。经常需要查询,不经常修改的数据,不是特别重要的数据都适合于存储到缓存中。 2.Mybatis缓存 mybatis包含了一个非常强大的查询缓存特性&#…...
第1章大型互联网公司的基础架构——1.6 RPC服务
你可能在1.1节的引言中注意到业务服务层包括HTTP服务和RPC服务,两者的定位不一样。一般来说,一个业务场景的核心逻辑都是在RPC服务中实现的,强调的是服务于后台系统内部,所谓的“微服务”主要指的就是RPC服务;而HTTP服…...
多个用户如何共用一根网线传输数据
前置知识 一、电信号 网线(如以太网线)中传输的信号主要是 电信号,它携带着数字信息。这些信号用于在计算机和其他网络设备之间传输数据。下面是一些关于网线传输信号的详细信息: 1. 电信号传输 在以太网中,数据是…...
