网络编程(二)TCP编程 TCP粘包问题

文章目录

  • 一、TCP网络编程
    • (一)流程
    • (二)相关函数
      • 1. socket
      • 2. bind
      • 3. listen
      • 4. accept
      • 5. connect
  • 二、收发函数
    • (一)send函数
    • (二)recv函数
  • 三、TCP粘包问题
    • (一)将两次消息间隔一定时间后再发送
    • (二)关闭Nagle算法
    • (三)定长发送数据
  • 四、TCP下载程序

一、TCP网络编程

网络编程模型:
C/S模型:客户端服务器模型
优点:
客户端可以缓存一些数据,使用时直接在本地读取,无需每次重新下载;
由于客户端和服务器都是自己开发的,可以自定义协议
缺点:代码开发量大

B/S模型:浏览器服务器模型
优点:代码开发量较小
缺点:
客户端不能缓存数据,每次使用都需要重新从服务器端下载;
必须遵循http协议

(一)流程

在这里插入图片描述
服务器流程
创建套接字–socket()
填充服务器的网络信息结构体
将套接字与服务器网络信息结构体绑定–bind()
将套接字设置成被动监听状态–listen()
阻塞等待客户端连接–accept()
收发数据–write()/read()
关闭套接字–close()

客户端流程
创建套接字–socket()
填充服务器的网络信息结构体
(可以绑定,即指定端口号与服务器通信;可以不绑定,系统会分配一个临时端口号用于与服务器通信)
与服务器建立连接–connect()
收发数据–write()/read()
关闭套接字–close()

(二)相关函数

1. socket

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:
    创建套接字
参数:
    domain:通信域
        AF_UNIX  AF_LOCAL  本地通信使用
        AF_INET            IPV4使用
        AF_INET6          IPV6使用
        AF_PACKET          原始套接字使用
    type:套接字类型
        SOCK_STREAM      TCP使用
        SOCK_DGRAM       UDP使用
    protocol:附加协议 传0 表示没有附加协议
返回值:
    成功  套接字(文件描述符)
    失败  -1  重置错误码

2. bind

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
    将套接字与服务器网络信息结构体绑定
参数:
    sockfd:套接字
    addr:网络信息结构体的首地址
        struct sockaddr {
            sa_family_t sa_family;
            char        sa_data[14];
        }
        //上面的结构体只是用来强转 防止编译警告的 
        //实际使用的是下面的结构体
        struct sockaddr_in {
            sa_family_t    sin_family; /* AF_INET */
            in_port_t      sin_port;   /* 网络字节序的端口号 */
            struct in_addr sin_addr;   /* 网络地址 */
        };
        struct in_addr {
            uint32_t       s_addr;     /* 网络字节序无符号4字节整型的IP地址 */
        };
    addrlen:addr的长度
返回值:
    成功  0
    失败  -1  重置错误码

3. listen

#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:
    将套接字设置成被动监听状态
参数:
    sockfd:套接字
    backlog:指定半连接队列的最大长度
            一般传 5  10  等都可以 不是 0 就行
            //因为我们实际开发时 一般都是并发服务器 基本能维持半连接队列中没有元素
返回值:
    成功  0
    失败  -1  重置错误码

4. accept

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
    提取半连接队列中的第一个链接,会返回一个新的套接字专门用于和该客户端通信
    如果半连接队列中没有连接请求 accept函数会阻塞等待客户端连接
参数:
    sockfd:套接字 必须是已经绑定了本地地址 且置成被动监听状态的
    addr:用于保存客户端的网络信息结构体的缓冲区的首地址 不关心可以传NULL
    addrlen:addr的大小,不关心也可以传NULL
返回值:
    成功  新的套接字用于收发数据
    失败  -1  重置错误码

5. connect

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
    与服务器建立连接
参数:
    sockfd:套接字
    addr:要连接的服务器的网络信息结构体的首地址
    addrlen:addr的长度
返回值:
    成功  0
    失败  -1  重置错误码

二、收发函数

(一)send函数

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
    向套接字上发送一条消息
参数:
    sockfd:套接字
    buf:要发送的数据的首地址
    len:想要发送的字节数
    flags:标志位  0  阻塞   MSG_DONTWAIT 非阻塞
返回值:
    成功 实际发送的字节数
    失败 -1 重置错误码
    如果对方关闭了套接字或者断开连接,第一次send没有任何现象
    但是第二次send会产生一个SIGPIPE
    
等价关系:
write(sockfd, buff, sizeof(buff));
send(sockfd, buff, sizeof(buff), 0);
sendto(sockfd, buff, sizeof(buff), 0, NULL, 0);

(二)recv函数

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
    在套接字上接收一条消息
参数:
    sockfd:套接字
    buf:用来存放接收到的数据的缓冲区的首地址
    len:想要接收的字节数
    flags:标志位  0  阻塞   MSG_DONTWAIT 非阻塞
返回值:
    成功 实际接收的字节数
    失败 -1 重置错误码
    TCP的套接字,如果对方断开连接或者关闭套接字,recv会返回0
    
等价关系:
read(sockfd, buff, sizeof(buff));
recv(sockfd, buff, sizeof(buff), 0);
recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);

三、TCP粘包问题

TCP协议中有一个Nagle 算法,他会通过减少数据包发送量来增进TCP/IP网上的性能。如果当前有一个部分填写的报文段(即还有可用空间可添加数据)在等待发送,那么就等到这个报文段填满或者达到最大延迟时间后再发送。
因为数据是没有边界的,因此可能会导致接收方在接收到数据后无法正常解析数据。

(一)将两次消息间隔一定时间后再发送

服务器程序中禁止使用sleep函数

(二)关闭Nagle算法

int value = 1;
setsockopt(sock_fd,IPPROTO_TCP,TCP_NODELAY,(char*)&value,sizeof(int));

(三)定长发送数据

还可以在包的开头标注有效数据长度。

四、TCP下载程序

server.c


client.c


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux精通 4.1

2.1.3 http服务器实现 目的 reactor应用——webserver webclient 每次上课前 看大纲down code 复习&#xff1a; 不行啊 编译给的代码报错啊 给的最新的不是0430那一版就不行啊 reactor.c:(.text0x254): relocation truncated to fit: R_X86_64_PC32 against symbol begin de…

Gobject tutorial 八

The GObject base class Object memory management Gobject的内存管理相关的API很复杂&#xff0c;但其目标是提供一个基于引用计数的灵活的内存管理模式。 下面我们来介绍一下&#xff0c;与管理引用计数相关的函数。 Reference Count 函数g_object_ref和g_object_unref的…

车载测试面试项目看这一套就够了!车载测试___自我讲解项目

面试官您好&#xff0c;我叫xx来自安微&#xff0c;今年xx岁&#xff0c;毕业于安微新华学院&#xff0c;我是从2017年开始接触软件测试行业&#xff0c;目前从事软件测试工作有5年多时间&#xff0c;第一家公司做了电商和进销存项目app和web都有做过&#xff0c;上家公司做了车…

Python使用策略模式实现绘图功能

策略模式&#xff08;Strategy Pattern&#xff09;:允许定义一系列算法&#xff0c;将它们封装起来&#xff0c;使得它们可以互换。 实现绘制不同类型的图表&#xff08;如折线图、柱状图和饼图&#xff09;功能。 下面是一个示例&#xff0c;展示如何传入横坐标和纵坐标内容…

Spring Boot集成tablesaw插件快速入门

1 什么是tablesaw&#xff1f; Tablesaw是一款Java的数据可视化库&#xff0c;主要包括两部分&#xff1a; 数据解析库&#xff0c;主要用于加载数据&#xff0c;对数据进行操作(转化&#xff0c;过滤&#xff0c;汇总等)&#xff0c;类比Python中的Pandas库&#xff1b; 数据…

JVM中的垃圾回收机制

文章目录 什么是垃圾为什么需要垃圾回收早期垃圾回收Java的垃圾回收机制垃圾回收主要关注的区域垃圾判定算法引用计数算法可达性分析算法 垃圾收集算法标记清除算法复制算法标记整理算法分代收集思想增量收集算法分区算法 什么是垃圾 垃圾回收&#xff08;Garbage Collection&…

Java面试八股之Mybatis和JPA的区别

Mybatis和JPA的区别 Mybatis 和 JPA&#xff08;Java Persistence API&#xff09;是两种在 Java 应用程序中用于数据持久化的框架&#xff0c;它们各有特点和适用场景。下面是它们之间的一些主要区别&#xff1a; 映射方式&#xff1a; Mybatis 是半自动的 ORM 框架&#xf…

Vue66-vue-默认插槽

一、默认插槽需求 1-1、原本的写法&#xff1a; 在每个category组件中用v-show来做条件渲染&#xff0c;但是不方便&#xff01; 1-2、默认插槽 img标签&#xff0c;ul标签&#xff0c;video标签&#xff0c;都是在app组件中完成解析之后&#xff0c;塞到category组件中的&…

实验室装修公司教你:真菌实验室设计建设的必备技巧

在当今的科学研究和生物技术领域&#xff0c;真菌实验室设计建设显得尤为重要。然而&#xff0c;很多实验室在实际操作中常常面临空间布局不合理、设备配置不当以及环境控制不到位等诸多挑战&#xff0c;导致实验效率低下&#xff0c;甚至危及人员安全。那么要怎么才能设计建设…

【Unity】AssetBundle打包策略

【Unity】AssetBundle打包策略 在游戏开发过程中&#xff0c;AssetBundle(AB)打包策略的重要性不容忽视。游戏开发者往往手动设置游戏资源包名进行管理&#xff0c;难免会造成资源确实或导致冗余&#xff0c;因此对于AB包的打包流程来说&#xff0c;进行策略管理显得十分重要。…

卓越的 App UI 风格引领潮流

卓越的 App UI 风格引领潮流

fastadmin多语言切换设置

fastadmin版本&#xff1a;1.4.0.20230711 以简体&#xff0c;繁体&#xff0c;英文为例 一&#xff0c;在application\config.php 里开启多语言 // 是否开启多语言lang_switch_on > true, // 允许的语言列表allow_lang_list > [zh-cn, en,zh-tw], 二…

Linux环境编程基础学习2

For循环累加求和&#xff0c;两种方式&#xff0c;c方式的运算更快 打开文件操作 cat操作的实现 EOF: 1.diff A B比较两个文件是否一样&#xff0c;一样则什么结果都没有 Od -c 文件名可以显示出文件中的不可见字符

Stable Diffusion WebUI 使用ControlNet:IP-Adapter保持生图的角色一致性

IP-Adapter-FaceID可以在保持人脸一致的条件下生成各种风格的图像。 下载 IP Adapter 需要的 Face ID 模型和 Lora 下载地址&#xff1a;https://huggingface.co/h94/IP-Adapter-FaceID/ 下载 ip-adapter-faceid-plusv2_sd15.bin 和 ip-adapter-faceid-plusv2_sd15_lora.saf…

Linux:文件描述符

文件描述符实际上就是一个小整数 0 & 1 & 2 Linux进程默认情况下会有3个缺省打开的文件描述符&#xff0c;分别是标准输入0&#xff0c; 标准输出1&#xff0c; 标准错误2. 0,1,2对应的物理设备一般是&#xff1a;键盘&#xff0c;显示器&#xff0c;显示器 所以输入输…

SpingBoot快速入门下

响应HttpServietResponse 介绍 将ResponseBody 加到Controller方法/类上 作用&#xff1a;将方法返回值直接响应&#xff0c;如果返回值是 实体对象/集合&#xff0c;将会自动转JSON格式响应 RestController Controller ResponseBody; 一般响应 统一响应 在实际开发中一般…

多线程下JVM内存模型 和 volatile关键字

1、线程的概念 线程&#xff08;thread&#xff09;是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流&#xff0c;一个进程中可以并发多个线程&#xff0c;每条线程并行执行不同的任务…

20240620每日一题-测试瓶子的硬度

小明用2个玻璃瓶&#xff0c;在总高88层大楼测试瓶子硬度&#xff0c;拿1个瓶子从某层摔下去&#xff0c;瓶子没摔碎&#xff0c;到更高层去摔&#xff0c;如果碎了&#xff0c;拿另1瓶子到更低层摔 问测试出瓶子最大硬度最少摔几次&#xff1f; 分析 1只有1个瓶子 为了保证…

C语言数据存储大小端问题

大小端 什么是大小端 大端模式&#xff08;Big-endian&#xff09;&#xff0c;是指数据的高字节&#xff0c;保存在内存的低地址中&#xff0c;而数据的低字节&#xff0c;保存在内存的高地址中; 小端模式&#xff08;Little-endian&#xff09;&#xff0c;是指数据的高字…

静态网页处理复杂请求

目录 1.定制请求头 (1)&#xff0e;查看请求头 (2)&#xff0e;设置请求头 2.验证 Cookie 3.保持会话 4. SSL 证书验证 在互联网中&#xff0c;网页中的内容是千变万化的&#xff0c;如果只根据请求 URL 发送基本请求&#xff0c;则可能 无法获取网站的响应数据&#xff0…