当前位置: 首页 > news >正文

【Linux Day15 TCP网络通讯】

TCP网络通讯

TCP编程流程

在这里插入图片描述

接口介绍

  • socket()方法是用来创建一个套接字,有了套接字就可以通过网络进行数据的收发。创建套接字时要指定使用的服务类型,使用 TCP 协议选择流式服务(SOCK_STREAM)。

  • **bind()方法是用来指定套接字使用的 IP 地址和端口。**IP 地址就是自己主机的地址,测试程序时可以使用回环地址“127.0.0.1”。端口是一个 16 位的整形值,一般 0-1024 为知名端口,如 HTTP 使用的 80 号端口。这类端口一般用户不能随便使用。其次,1024-4096 为保留端口,用户一般也不使用。4096 以上为临时端口,用户可以使用。在Linux 上,1024 以内的端口号,只有 root 用户可以使用。

  • **listen()方法是用来创建监听队列。**监听队列有两种,一个是存放未完成三次握手的连接,一种是存放已完成三次握手的连接。listen()第二个参数就是指定已完成三次握手队列的长度。

  • accept()处理存放在 listen 创建的已完成三次握手的队列中的连接。每处理一个连接,则accept()返回该连接对应的套接字描述符。如果该队列为空,则 accept 阻塞。

  • connect()方法一般由客户端程序执行,需要指定连接的服务器端的 IP 地址和端口。该方法执行后,会进行三次握手, 建立连接。

  • send()方法用来向 TCP 连接的对端发送数据。send()执行成功,只能说明将数据成功写入到发送端的发送缓冲区中,并不能说明数据已经发送到了对端。send()的返回值为实际写入到发送缓冲区中的数据长度。

  • recv()方法用来接收 TCP 连接的对端发送来的数据。recv()从本端的接收缓冲区中读取数据,如果接收缓冲区中没有数据,则 recv()方法会阻塞;返回值是实际读到的字节数,如果recv()返回值为 0, 说明对方已经关闭了 TCP 连接。

  • close()方法用来关闭 TCP 连接。此时,会进行四次挥手

客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);assert(sockfd != -1);struct sockaddr_in saddr;memset(&saddr, 0, sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));if (-1 == res){ exit(1);}while (1){char buff[128] = {0};printf("input:\n");fgets(buff, 128, stdin);if (strncmp(buff, "end", 3) == 0){break;}send(sockfd, buff, strlen(buff), 0);memset(buff, 0, 128);recv(sockfd, buff, 127, 0);printf("buff=%s\n", buff);}close(sockfd);exit(0);
}

服务端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){exit(1);}struct sockaddr_in saddr;memset(&saddr, 0, sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);                   // htons 将主机字节序转换为网络字节saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 回环地址int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));if (-1 == res){exit(1);}res = listen(sockfd, 5);if (-1 == res){exit(1);}struct sockaddr_in caddr;socklen_t len = sizeof(caddr);int n = 0;int c = -1;while (1) // 服务器循环接收客户端连接{char data[128] = {0};if (n == 0){c = accept(sockfd, (struct sockaddr *)&caddr, &len); // 阻塞if (c == -1){printf("accept error ");continue;;}}n = recv(c, data, 127, 0); // 阻塞if (n == 0)                //连接关闭{close(c);printf("client close\n");continue;}else if (n < 0)            //出错{printf("recv error");continue;}printf("n = %d, buff = %s\n", n, data);send(c, "OK", 2, 0);}close(sockfd); exit(0);
}

运行结果:

引入多线程处理并发

服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>void *run(void *arg)
{int c = (int)arg;while (1){char buff[128] = {0};if (recv(c, buff, 127, 0) <= 0){break;}printf("recv(%d)=%s", c, buff);send(c, "ok", 2, 0);}printf("one client over(%d)\n", c);close(c);
}int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){exit(1);}struct sockaddr_in saddr, caddr;memset(&saddr, 0, sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));if (-1 == res){exit(1);}listen(sockfd, 10);while (1){int len = sizeof(caddr);int c = accept(sockfd, (struct sockaddr *)&caddr, &len);if (c < 0){continue;}printf("accept c = %d\n", c);pthread_t id;pthread_create(&id, NULL, run, (void *)c);}close(sockfd);exit(0);
}

运行结果:

引入fork处理并发

服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>void DealClientLink(int c, struct sockaddr_in caddr)
{while (1){char buff[128] = {0};int n = recv(c, buff, 127, 0);if (n <= 0){break;}printf("%s:%d %s", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buff);send(c, "OK", 2, 0);}printf("One Client Close\n");close(c);
}void Signal_Fun(int sign)
{wait(NULL);
}
int main()
{signal(SIGCHLD, Signal_Fun); // 用wait()处理僵死进程int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){printf("create sockfd error\n");exit(1);}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));assert(-1 != res);listen(sockfd, 10);while (1){struct sockaddr_in caddr;int len = sizeof(caddr);int c = accept(sockfd, (struct sockaddr *)&caddr, &len);assert(-1 != c);printf("%s:%d Link Success\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));pid_t pid = fork();if (-1 == pid){exit(1);}if (0 == pid){DealClientLink(c,caddr);exit(0);   //必须结束子进程,否则会有多个进程调 accept}else{close(c);  //父子进程都需要关闭 c}}close(sockfd);exit(0);
}

运行结果:

TCP连接状态转变图

三次握手

  • 流程图

  • 使用netstat工具查看状态变化(参考图3-8)

四次挥手

  • 流程图

  • 使用netstat命令查看状态(参考图3-8)

TIME_WAIT的作用

在图3-8中,当客户端连接在收到服务器的结束报文段之后,并没有直接进人CLOSED 状态,而是转移到 TIME_WAIT 状态。在这个状态,客户端连接要等待段长为2MSL(Maximum Segment Life,报文段最大生存时间)的时间,才能完全关闭;MSL是 TCP 报文段在网络中的最大生存时间,标准文档 RFC 1122 的建议值是2 min;

TIME WAIT 状态存在的原因有两点:
  1. 可靠地终止TCP 连接

    当服务器发给客户端的ACK中途丢失,客户端收不到ACK,会重新发送FIN,如果此时服务器已经关闭,无法接收来自客户端的FIN,便会陷入一种“藕断丝连”状态(一方关闭,一方未关闭)。这显然是不合适的,因为TCP 连接是全双工的,双方完成数据交换之后,通信双方都必须断开连接以释放系统资源

  2. 保证让迟来的TCP 报文段有足够的时间被识别并丢弃

    在 Linux 系统上,一个TCP 端口不能被同时打开多次(两次及以上)。当一个TCP 连接处于 TIME_WAIT 状态时,我们将无法立即使用该连接占用着的端口来建立一个新连接。反过来,如果不存在 TIME WAIT 态,则应用序能够立即建立一个和刚关闭的连接相似的连接(这里说的相似,是指它们具有相同的 IP 地址和端口号)。这个新的、和原来相似的连接被称为原来的连接的化身 (incarmation)。新的化身可能接收到属于原来的连接的、携带应用程序数据的 TCP 报文段(迟到的报文段),这显然是不应该发生的。这就是 TIMEWAIT 状态存在的第二个原因。

TCP协议特点

流式服务

TCP 字节流的特点,发送端执行的写操作次数和接收端执行的读操作次数之间没有任何数量关系,应用程序对数据的发送和接收是没有边界限制的。如下图:

TCP连接的可靠性

  • IPV4报文格式:

  • TCP报文格式:

  • 应答机制

  • 超时重传

TCP 传输是可靠的。首先,TCP 协议采用发送应答机制,即发送端发送的每个 TCP 报文段都必须得到接收方的应答,才认为这个 TCP 报文段传输成功。其次,TCP 协议采用超时重传机制,发送端在发送出1个 TCP 报文段之后启动定时器,如果在定时时间内未收到应答,它将重发该报文段。最后,因为 TCP 报文段最终是以 IP数据报发送的,而 数据报到达接收端可能乱序、重复,所以 TCP 协议还会对接收到的 TCP 报文段重排、整理,再交付给应用层。

粘包问题

在流式服务中如上图3-9所示,尽管报文已经按顺序整理好并接受,但是无法分割成正确的信息,就形成了所谓的粘包问题,为了解决此问题,我们可以每次发送时进行标记分割,以便于接收方进行分析和拆分,如下图:

相关文章:

【Linux Day15 TCP网络通讯】

TCP网络通讯 TCP编程流程 接口介绍 socket()方法是用来创建一个套接字&#xff0c;有了套接字就可以通过网络进行数据的收发。创建套接字时要指定使用的服务类型&#xff0c;使用 TCP 协议选择流式服务&#xff08;SOCK_STREAM&#xff09;。 **bind()方法是用来指定套接字使…...

力扣:78. 子集

回溯解法思路&#xff1a; 1.跟前面的组合题目有相同的点&#xff0c;主要区别在于&#xff1a;组合题目是遍历到符合条件的组合时加入li1集合中&#xff0c;子集题目是每递归一次就要把结果加入到li1集合中&#xff0c;并遍历但nums数组的最后。其他点和组合问题一样。 clas…...

(29)数组异或操作

文章目录 每日一言题目解题思路方法一方法二 代码方法一方法二 结语 每日一言 泉涸&#xff0c;鱼相与处于陆&#xff0c;相呴以湿&#xff0c;相濡以沫&#xff0c;不如相忘于江湖。 --庄子内篇大宗师 题目 题目链接&#xff1a;数组异或操作 给你两个整数&#xff0c;n 和…...

mac检查CPU温度和风扇速度软件:Macs Fan Control Pro 1.5.17中文版

Macs Fan Control Pro for Mac是一款专业的电脑风扇控制工具&#xff0c;旨在帮助Mac用户有效控制电脑的风扇速度&#xff0c;提高电脑的运行效率和稳定性。 软件下载&#xff1a;Macs Fan Control Pro 1.5.17中文版 该软件支持多种风扇控制模式和预设方案&#xff0c;用户可以…...

数据结构——单链表详解

目录 前言 一.什么是链表 1.概念 ​编辑 2.分类 二.单链表的实现(不带头单向不循环链表) 2.1初始化 2.2打印 2.3创建新节点 2.4头插、尾插 2.5头删、尾删 2.6查找 2.7在指定位置之前插入 2.8在指定位置之后插入 2.9删除pos位置 2.10删除pos之后的 2.11销毁链表…...

Unity接入GVoice腾讯实时语音

Unity接入GVoice腾讯实时语音 一、介绍二、注册GVoice创建项目语音服务1.创建项目2.申请语音权限3.项目管理查看SDK初始化的一些参数和基本信息4.GVoice检测 三、SDK下载SDK是分为两种类型&#xff1a;独立版集成板 SDK放入Unity工程中 四、语音代码写法五、GVoice踩坑语音权限…...

【Spring基础】从0开始学习Spring(2)

前言 在上篇文章&#xff0c;我已经讲了Spring中最核心的知识点&#xff1a;IoC&#xff08;控制反转&#xff09;以及DI&#xff08;依赖注入&#xff09;。这篇文章&#xff0c;我将讲一下关于Spring框架中的其它比较琐碎但是又还是挺重要的知识点&#xff0c;因此&#xff…...

cesium mapboxgl+threebox glb 朝向问题

一、3Dbuilder打开glb 二、cesium在pitch和heading都为0的情况下&#xff0c;不设置模型的朝向 三、mapboxglthreebox在pitch和bearing都为0的情况下&#xff0c;不设置模型的朝向 四、对于地图默认视角&#xff0c;cesium设置pitch-90、heading0的时候和mapboxglthreebox设置p…...

LeetCode 打家劫舍

198. 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个…...

单片机的50个电路

单片机 电源 声音模块 收音机 485 蓝牙 光耦 can 光敏电阻 单片机 矩阵 单片机电路 时钟 ADC 接口电路 红外发射 显示模块 红外接收 蜂鸣器驱动 流水灯 usb供电 烧录电路 数码管 EEPROM LCD1602电路 数码管 max485 红外开关 译码器 移位寄存器 步进电机控制 复位电路 下载电路 …...

JVM 性能调优- 五种内存溢出(5)

在介绍之前先简单介绍下 直接内存(Direct Memory)和堆内存(Heap Memory): 关系: 直接内存并不是Java虚拟机的一部分,它是通过Java的NIO库中的ByteBuffer来分配和管理的。直接内存通常由操作系统的本地内存(Native Memory)提供支持。堆内存是Java虚拟机的一部分,用于存…...

【SQL高频基础】1141.查询近30天活跃用户数

题目&#xff1a; 表&#xff1a;Activity ------------------------ | Column Name | Type | ------------------------ | user_id | int | | session_id | int | | activity_date | date | | activity_type | enum | ------------------------…...

基于spring cloud alibaba的微服务平台架构规划

平台基础能力规划&#xff08;继续完善更新…&#xff09; 一、统一网关服务&#xff08;独立服务&#xff09; 二、统一登录鉴权系统管理&#xff08;独立服务&#xff09; 1.统一登录 2.统一鉴权 3.身份管理 用户管理 角色管理 业务系统和菜单管理 部门管理 岗位管理 字典管…...

leetcode(滑动窗口)3.无重复字符的最长字串(C++详细题解)DAY2

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示…...

Android13 系统源码适配安装可卸载的三方apk应用

Android13 系统源码适配安装可卸载的三方apk应用 文章目录 Android13 系统源码适配安装可卸载的三方apk应用一、前言二、Android 系统运行后默认安装三方apk实现1、Android 系统默认安装三方apk实现主要思路2、Android 系统默认安装三方apk具体实现&#xff08;1&#xff09;准…...

flutter使用qr_code_scanner扫描二维码

qr_code_scanner仓库地址&#xff1a;qr_code_scanner | Flutter Package 需要添加android和ios的相机权限和本地相册权限&#xff1a; android中添加权限: 在android\app\build.gradle中修改&#xff1a;minSdkVersion 20 并且在android/app/src/main/AndroidManifest.xml中…...

黑马Java——集合进阶(List、Set、泛型、树)

一、集合的体系结构 1、单列集合&#xff08;Collection&#xff09; 二、Collection集合 1、Collection常见方法 1.1代码实现&#xff1a; import java.util.ArrayList; import java.util.Collection;public class A01_CollectionDemo1 {public static void main(String[] a…...

TS项目实战二:网页计算器

使用ts实现网页计算器工具&#xff0c;实现计算器相关功能&#xff0c;使用tsify进行项目编译&#xff0c;引入Browserify实现web界面中直接使用模块加载服务。   源码下载&#xff1a;点击下载 讲解视频 TS实战项目四&#xff1a;计算器项目创建 TS实战项目五&#xff1a;B…...

MySQL的ACID、死锁、MVCC问题

1 ACID ACID代表原子性&#xff08;atomicity&#xff09;、一致性&#xff08;consistency&#xff09;、隔离性&#xff08;isolation&#xff09;和持久性&#xff08;durability&#xff09;。一个确保数据安全的事务处理系统&#xff0c;必须满足这些密切相关的标准。 原…...

Docker 可视化工具

1、Portainer 概念介绍 Portainer是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 Portainer分为开源社区版&#xff08;CE版&#xff09;和商用版&#xff08;BE版/EE版&#xff09;。 Porta…...

【C++】友元:友元函数与友元类

一、友元 友元&#xff08;friend&#xff09;是C中的一种特殊关系&#xff0c;用于在类之间共享访问权限。通过将一个函数或类声明为另一个类的友元&#xff0c;我们可以允许友元访问声明类的非公有成员。 二、友元函数 问题&#xff1a;现在尝试去重载operator<<&am…...

linux之wsl2安装远程桌面

0. 安装后的效果 1. wsl中打开terminal并安装库 sudo apt-get purge xrdp sudo apt install -y xrdp sudo apt install -y xfce4 sudo apt install -y xfce4-goodies 2.优化显示 sudo sed -i s/max_bpp32/#max_bpp32\nmax_bpp128/g /etc/xrdp/xrdp.ini sudo sed -i s/xserverbp…...

如何以管理员身份删除node_modules文件

今天拉项目&#xff0c;然后需要安装依赖&#xff0c;但是一直报错&#xff0c;如下&#xff1a; 去搜这个问题会让把node_modules文件先删掉 再去安装依赖。我在删除的过程中会说请以管理员身份来删除。 那么windows如何以管理员身份删除node_modules文件呢&#xff1f; wi…...

【Linux】环境基础开发工具的使用之gdb详解(三)

前言&#xff1a;上一篇文章中我们讲解了Linux下的gcc与g的使用&#xff0c;今天我们将进一步的学习gdb与makefile来帮我们更好的理解与使用基础开发工具。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:Linux的深度刨析 &#x1f448; …...

SpringBoot源码解读与原理分析(二十四)IOC容器的刷新(五)

文章目录 7.11 初始化所有剩下的单实例bean对象7.11.1 beanFactory.preInstantiateSingletons7.11.2 getBean7.11.2.1 别名的解析处理7.11.2.2 判断是否已注册过7.11.2.3 创建前的检查7.11.2.4 标记准备创建的bean对象7.11.2.5 合并BeanDefinition7.11.2.6 bean对象的创建7.11.…...

最大子数组和

一、题目 给你一个整数数组nums&#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#…...

Node.js版本管理工具之_Volta

Node.js包管理工具之_Volta 文章目录 Node.js包管理工具之_Volta1. 官网1. 官网介绍2. 特点1. 快( Fast)2. 可靠(Reliable)3. 普遍( Universal) 2. 下载与安装1. 下载2. 安装3. 查看 3. 使用1. 查看已安装的工具包2. 安装指定的node版本3.切换项目中使用的版本 1. 官网 1. 官网…...

Redis 命令大全

文章目录 启动与连接Key&#xff08;键&#xff09;相关命令String&#xff08;字符串&#xff09;Hash&#xff08;哈希&#xff09;List&#xff08;列表&#xff09;Set&#xff08;集合&#xff09;Sorted Set&#xff08;有序集合&#xff09;其他常见命令HyperLogLog&…...

再这么烂下去,离糊就不远了。别让才华被埋没。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 近日&#xff0c;胡歌凭借电视剧《繁花》荣登《环球银幕》二月…...

Unity BuffSystem buff系统

Unity BuffSystem buff系统 一、介绍二、buff系统架构三、架构讲解四、框架使用buff数据Json数据以及工具ShowTypeBuffTypeMountTypeBuffOverlapBuffShutDownTypeBuffCalculateType时间和层数这里也不过多说明了如何给生物添加buff 五、总结 一、介绍 现在基本做游戏都会需要些…...