TCP开发

news2025/2/22 4:13:12

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_addr
    struct 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 固定,并获取一定的对外访问权限。理论上,这样搭建的服务器可被全国范围内的用户通过网络连接。但实际上,运营商通常不会支持此类操作。较为可行的做法是将服务器程序部署到阿里云、百度云、腾讯云等云服务器上,如此一来,全球任何位置的用户都能访问该服务器程序。

服务器程序的开发流程:

  1. 需要创建一个TCP的套接字----socket()
  2. 绑定服务器的属性(IP地址、端口号)----bind()
  3. 监听->监测/允许链接的最大数----listen()
  4. 接收客户端的链接----accept()
  5. 与客户端通信----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);
    }
}

实验现象: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2301605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 基于SpringBoot+Vue 的旅游网站信息化管理系统设计与实现

Java 基于SpringBootVue 的旅游网站信息化管理系统设计与实现 博主介绍&#xff1a;✌程序员徐师兄、8年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战*✌ &#x1f345;文末获取源码联系&#x1f34…

Ubuntu:20.04更新cmake到更高版本

从输出信息可以看出&#xff0c;您当前的系统中已经安装了 cmake&#xff0c;但版本是 3.16.3&#xff0c;而您的项目需要 CMake 3.18 或更高版本。默认情况下&#xff0c;Ubuntu 20.04 的官方软件仓库中提供的 CMake 版本较低&#xff08;如 3.16.3&#xff09;&#xff0c;因…

php 系统命令执行及绕过

文章目录 php的基础概念php的基础语法1. PHP 基本语法结构2. PHP 变量3.输出数据4.数组5.超全局变量6.文件操作 php的命令执行可以执行命令的函数命令执行绕过利用代码中命令&#xff08;如ls&#xff09;执行命令替换过滤过滤特定字符串神技&#xff1a;利用base64编码解码的绕…

论文笔记-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&#xff0c;大家好&#xff0c;我们又满血复活了。 2025年开年更新频率不快&#xff0c;一方面是大模型如火如荼&#xff0c;也一直在补相关知识&#xff1b;另外一方面&#xff0c;新的一年里身体健康被我摆到了第一位&#xff0c;不会像前几年那么卷了。 后续我们的更新会…

Vue前端开发-Vant组件之Button组件

Vant 有丰富的UI组件&#xff0c;而基础组件是全部组件的核心&#xff0c;基础组件中将常用的元素做了二次的开发&#xff0c;封装成Vant格式组件&#xff0c;如按钮、图片和布局等&#xff0c;这些封装后的Vant组件&#xff0c;提供了更多面向实际应用的属性和事件&#xff0c…

DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)

前言 在当今数字化时代&#xff0c;AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型&#xff0c;凭借其出色的性能和开源免费的优势&#xff0c;成为许多开发者的首选。今天&#xff0c;就让我们一起探索如何将DeepSeek接入PyCharm&#xff0c;实现高效、智…

【Linux网络编程】应用层协议HTTP(请求方法,状态码,重定向,cookie,session)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux网络编程 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ Linux网络编程笔记&#xff1a; https://blog.cs…

健康养生:从生活细节开启活力之旅

在忙碌的现代生活里&#xff0c;健康养生不再是一个抽象概念&#xff0c;而是关乎生活质量的关键。其实&#xff0c;只要掌握日常养生要点&#xff0c;就能轻松开启活力满满的健康生活。 饮食是健康的基石。每日饮食需遵循 “彩虹原则”&#xff0c;摄入多种颜色食物。早餐时&…

DeepSeek + Mermaid编辑器——常规绘图

下面这张图出自&#xff1a;由清华大学出品的 《DeepSeek&#xff1a;从入门到精通》。 作为纯文本生成模型&#xff0c;DeepSeek虽不具备多媒体内容生成接口&#xff0c;但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作&#xff0c;最终…

【拥抱AI】GPT Researcher的诞生

一、GPT Researcher 研究过程总结 GPT Researcher 是一个开源的自主智能体&#xff0c;旨在通过利用人工智能技术实现高效、全面且客观的在线研究。它通过一系列创新的设计和优化&#xff0c;解决了传统研究工具&#xff08;如 AutoGPT&#xff09;中存在的问题&#xff0c;如…

Redis7——基础篇(三)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09; 接上期内容&#xff1a;上期完成了Redis的基本…

MySQL登录问题总结

不管何种数据库&#xff0c;使用的第一步都是先登录。 MySQL命令行登录语句&#xff1a;mysql -u username -P port -p -D database_name 登录MySQL的报错一般从报错信息都能得到反馈&#xff0c;常见报错原因分析如下&#xff0c;实例中的以test用户为例&#xff0c;登录环境为…

Redis 持久化:从零到掌握

Redis 作为一款广泛使用的内存数据库&#xff0c;虽然核心功能是基于内存提供高性能的数据存取&#xff0c;但在实际应用中&#xff0c;数据的持久化是不可忽视的。毕竟&#xff0c;内存中的数据一旦出现故障或重启&#xff0c;就会面临数据丢失的风险。因此&#xff0c;Redis …

Mybatis MyBatis框架的缓存 一级缓存

1. 缓存的概念 缓存的概念 在内存中临时存储数据&#xff0c;速度快&#xff0c;可以减少数据库的访问次数。经常需要查询&#xff0c;不经常修改的数据&#xff0c;不是特别重要的数据都适合于存储到缓存中。 2.Mybatis缓存 mybatis包含了一个非常强大的查询缓存特性&#…

第1章大型互联网公司的基础架构——1.6 RPC服务

你可能在1.1节的引言中注意到业务服务层包括HTTP服务和RPC服务&#xff0c;两者的定位不一样。一般来说&#xff0c;一个业务场景的核心逻辑都是在RPC服务中实现的&#xff0c;强调的是服务于后台系统内部&#xff0c;所谓的“微服务”主要指的就是RPC服务&#xff1b;而HTTP服…

idea-gradle打包运行配置

最近接触了一个项目&#xff0c;使用gradle做为构建工具&#xff0c;这里记录一波&#xff0c;毕竟平时使用的都是maven idea 配置 这里有个坑&#xff0c;Gradle Wrapper&#xff0c;配置的地址gradle下载超时 这个配置修改成阿里的 第一张 第二张 第二张配置的jvm貌似没啥用…

(新版本onenet)stm32+esp8266/01s mqtt连接onenet上报温湿度和远程控制(含小程序)

物联网实践教程&#xff1a;微信小程序结合OneNET平台MQTT实现STM32单片机远程智能控制 远程上报和接收数据——汇总 前言 之前在学校获得了一个新玩意&#xff1a;ESP-01sWIFI模块&#xff0c;去搜了一下这个小东西很有玩点&#xff0c;远程控制LED啥的&#xff0c;然后我就想…

一键部署开源DeepSeek并集成到钉钉

一键部署开源DeepSeek并集成到钉钉 简介&#xff1a; DeepSeek发布了两款先进AI模型V3和R1&#xff0c;分别适用于对话AI、内容生成及推理任务。由于官方API流量限制&#xff0c;阿里云推出了私有化部署方案&#xff0c;无需编写代码即可完成部署&#xff0c;并通过计算巢AppF…