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

linux下的网络编程:TCP(传输控制协议)编程

        

一、TCP概述

(一)特点     

           1. 面向数据包
2. 无连接
3. 尽最大努力交付,不安全不可靠(数据丢包、数据乱序)
4. 机制简单,资源开销小,数据实时性高
5. 可实现一对一、一对多的通信 

(二)TCP机制 ————“三次握手和四次挥手”

        各标志位

  • SYN : 请求建立连接标志位
  • ACK :响应报文标志位
  • FIN : 请求断开连接标志位

1)三次握手:TCP建立连接时,需要进行三次握手,为了确保收发双方通信之前都已准备就绪。

   

2)TCP四次挥手:TCP断开连接时,需要进行四次挥手,确保断开连接前双方都已通信结束。

二、TCP的编程过程

(一)TCP编程流程图

(二)核心函数

1.连接函数

连接函数int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能        请求与服务端建立连接
参数        sockfd:套接字
addr:要连接的服务端的地址信息
addrlen:服务端地址大小
返回值        成功:0
失败:-1

2.发送函数

发送函数ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能        发送网络数据
参数       sockfd:网络套接字
buf:要发送的数据首地址
len:发送的字节数
flags:0 :按照默认方式发送
     返回值       成功:实际发送的字节数
失败:-1

3.监听函数

int listen(int sockfd, int backlog);
功能监听建立三次握手的客户端
参数        sockfd:监听套接字
backlog:最大允许监听的客户端个数
返回值        成功:0
失败:-1

4.接收函数

int accept(int socket, struct sockaddr *restrict address,

                                                                                socklen_t *restrict  address_len);

功能接收建立三次握手的客户端,并产生一个通讯套接字
参数         socket:监听套接字
address:客户端的地址信息
address_len:客户端地址长的指针
返回值        成功:通讯套接字
失败:-1

5.从网络套接字上收取数据函数

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能从网络套接字上接收数据
参数         sockfd:通讯套接字
buf:存放接收数据的首地址
len:期望接收到的字节数
flag : 0:默认方式接收(阻塞)
返回值        成功:实际接收到的字节数
失败:-1
对方断开连接:0

(三)示例程序

实现功能:客户端不断从终端接收数据,使用TCP发送给服务端,服务端输出。

1.客户端

#include <stdio.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/types.h>          /* See NOTES */
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>int main(int argc,const char *argv[])
{//创建套接字int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.100.102");//请求建立连接int ret = connect(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));if(ret < 0){perror("connect error");return -1;}while(1){char buff[1024] = {0};fgets(buff,sizeof(buff),stdin);                    //从终端读取数据ssize_t cnt = send(sockfd,buff,strlen(buff),0);    //发送数据if(cnt < 0){perror("send error");return -1;}printf("cnt = %ld\n",cnt);}close(sockfd);                                    //关闭套接字return 0;
}

2.服务端

#include <stdio.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/types.h>          /* See NOTES */
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>int main(int argc,const char *argv[])
{//创建监听套接字——sockfdint sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.100.102");//绑定IP地址int ret = bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));if(ret < 0){perror("bind error");return -1;}//监听和服务端建立连接的客户端ret = listen(sockfd,10);if(ret < 0){perror("listen error");return -1;}//接收完成三次握手的客户端并产生一个通信套接字——connfdint connfd = accept(sockfd,NULL,NULL);if(connfd < 0){perror("accept error");return -1;}while(1){char buff[1024] = {0};ssize_t cnt = recv(connfd,buff,sizeof(buff),0); //接收数据if(cnt < 0){perror("recv error");return -1;}if(0 == cnt){break;}printf("cnt = %ld,buff = %s\n",cnt,buff);}close(sockfd);        //关闭监听套接字close(connfd);        //关闭通信套接字return 0;
}

三、TCP粘包问题

        TCP粘包问题:发送方应用层发送的多包数据,将来在接收方可能一次读到,多包数据产生了粘连。

1.产生原因

  • 发送方速度较快,TCP底层可能对多包数据进行重新组帧;
  •  接收方数据处理速度较慢,导致多包数据在接收缓冲区缓存,应用层读时,一次将多包数据读出。

2.解决方法

  • 调整发送速率
  • 发送指定大小,将来接收方也接受指定大小(即,使用结构体)。

 注意:
1. 跨平台之间的数据传输时,注意结构体对齐问题。
struct a
{
char a;
int b;
long c;
};
32bits平台和64位平台所占用的字节不同。

  • 应用层位发送的数据增加分隔符,利用分隔符解析(eg: hello world\nhow are you\n)
  • 封装自定义数据帧格式进行发送(协议),严格根据协议进行解析。

示例: 

AA  C0  00 00 00 F0 00 BB 10 A0  00 00 00 10 校验 BB  AA  C0  00 00 00 F0 00 BB 10 A0  00 00 00 10 校验 BB AA  C0  00 00 00 F0 00 BB 10 A0  00 00 00 10 校验 BB

帧头:AA
帧尾:BB
有效数据长度:C0
有效数据:00 00 00 F0 00 BB 10 A0  00 00 00 10
校验:
8位和校验
16位和校验
CRC校验

四、TCP的其他机制

(一)TCP的头部标志

     SYN:请求建立连接标志位
ACK:响应报文标志位
PSH:携带数据标志位,通知接收方该从缓冲区读数据
FIN: 请求断开连接标志位
RST:复位标志位
URG: 紧急数据标志位

(二)其他机制

1)确保其安全可靠

    1. 三次握手和四次挥手机制
2. 应答机制:TCP对于每一包数据都会给出相应的应答。发送数据时序列号表示这包数据的起始编号,响应报文中的确认号是接收方收到的最后一个字节编号+1。

     3. 超时重传机制:当数据发送出去等待指定时间没有收到响应,此时认为这包数据丢失则进行冲传。

     4. 滑动窗口机制:一段缓冲区,缓存TCP已发送未收到响应,准备发送等数据

2)提高效率

      1. 延迟应答机制:发送数据的同时可以等待应答。


2. 流量控制机制:结合TCP头部的窗口大小,动态调整发送速率。
3. 捎带应答机制:ACK报文可能和应用层的数据同时发送。

http://www.dtcms.com/a/352032.html

相关文章:

  • 数据结构(C语言篇):(一)算法复杂度
  • 复盘一个诡异的Bug之FileNotFoundException
  • 数据结构的线性表 之 链表
  • 二、JVM 入门——(三)栈
  • 动手学深度学习(pytorch版):第七章节—现代卷积神经网络(2)使用块的网络(VGG)
  • MyBatis 流式查询详解
  • 使用 mcp-use 构建极简 Web 自动化测试智能体「喂饭教程」
  • 前端漏洞(上)- CORS漏洞
  • 静态HTML网页模板设计与实现
  • python基础-面向对象编程(OOP)
  • 我们来学mysql -- safe启动
  • Mysql——日志
  • 【45页PPT】制造行业数据资产运营平台需求方案(附下载方式)
  • 【科研绘图系列】R语言在海洋生态学中的应用:浮游植物糖类组成与溶解性有机碳的关系
  • OpenCV打开视频函数VideoCapture使用详解
  • Linux桌面主题的安装
  • 33.ansible 比较重要的配置文件
  • 运算符(2)
  • 审核问题——鸿蒙审核返回安装失败,可以尝试云调试
  • timedatectl查看时间同步
  • Windows本地部署大模型方式对比
  • 约束满足问题(CSP)--搜索算法在实际场景中的应用
  • 深度学习篇---LeNet-5
  • 国产银河麒麟SP1桌面系统如何免密登录系统
  • Rust:函数与控制流
  • MATLAB在生态环境数据处理与分析中的应用
  • 基于MATLAB的雷达系统设计中的信号处理程序
  • Java:Docx4j类库简介及使用
  • 在 Vue 中嵌入 Unity WebGL 并实现双向通信
  • 有 100W 个数,有一个函数是可以高效查找并删除某个数,问应该用什么数据结构去存这 100W 个数