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

102.套接字-Socket网络编程4(TCP通信流程)

目录

TCP编程流程

 套接字函数

1.创建套接字

2.绑定地址

3.监听连接请求

4.接受连接

5. 连接到服务器

6. 发送数据

7. 接收数据

8.关闭套接字

服务器端通信流程 

示例代码

客户端通信流程

代码示例


TCP编程流程

TCP是一个面向连接的,安全的,流式传输协议,这个协议是一个传输层协议。

  • 面向连接:是一个双向连接,通过三次握手完成,断开连接需要通过四次挥手完成。
  • 安全:tcp通信过程中,会对发送的每一数据包都会进行校验, 如果发现数据丢失, 会自动重传
  • 流式传输:发送端和接收端处理数据的速度,数据的量都可以不一致。

TCP 的服务器端和客户端编程流程如下: 

 套接字函数

        套接字编程中,常用的套接字函数通常涵盖套接字的创建、绑定、监听、连接、发送、接收、关闭等操作。以下是一些常用的套接字函数,这些函数通常在C语言的<sys/socket.h>头文件中声明:

1.创建套接字

int socket(int domain, int type, int protocol);
  • 参数:

    • domain:使用的地址协议族,如 AF_INET、AF_INET6分别表示IPv4、IPv6格式。
    • type:套接字类型,如 SOCK_STREAM(流式传输协议)表示TCP套接字,SOCK_DGRAM(报式传输协议)表示UDP套接字。
    • protocol:通常为0,表示自动选择协议。
  • 返回值:

    • 成功:返回新创建套接字的文件描述符。
    • 失败:返回-1,并设置 errno

2.绑定地址

// 将文件描述符和本地的IP与端口进行绑定   
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:

    • sockfd:套接字的文件描述符,通过socket调用得到的返回值。
    • addr:包含要绑定的IP地址和端口号的结构体。
    • addrlenaddr 结构体的大小,sizeof(addr)。
  • 返回值:

    • 成功:0,失败:返回-1。

3.监听连接请求

// 给监听的套接字设置监听
int listen(int sockfd, int backlog);
  • 参数:

    • sockfd:套接字的文件描述符,通过socket调用得到的返回值。
    • backlog:在进入队列中等待接受的最大连接数,最大值为128。
  • 返回值:

    • 成功:0,失败:返回-1。

4.接受连接

// 等待并接受客户端的连接请求, 建立新的连接, 会得到一个新的文件描述符(通信的)		
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 参数:

    • sockfd:套接字的文件描述符。
    • addr:用于存储客户端地址信息的结构体。
    • addrlenaddr 结构体的大小。
  • 返回值:

    • 函数调用成功,得到一个文件描述符, 用于和建立连接的这个客户端通信,调用失败返回 -1。

这个函数是一个阻塞函数,当没有新的客户端连接请求的时候,该函数阻塞;当检测到有新的客户端连接请求时,阻塞解除,新连接就建立了,得到的返回值也是一个文件描述符,基于这个文件描述符就可以和客户端通信了。

5. 连接到服务器

// 成功连接服务器之后, 客户端会自动随机绑定一个端口
// 服务器端调用accept()的函数, 第二个参数存储的就是客户端的IP和端口信息
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:

    • sockfd:套接字的文件描述符,通过socket调用得到的返回值。
    • addr:用于存储客户端地址信息的结构体,这个IP和端口也需要转换为大端然后再赋值。
    • addrlenaddr 结构体的大小。
  • 返回值:

    • 连接成功返回0,连接失败返回-1

6. 发送数据

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 参数:

    • sockfd:套接字的文件描述符。
    • buf:包含要发送数据的缓冲区。
    • len:要发送的数据的长度。
    • flags:发送标志,通常为0。
  • 返回值:

    • 成功:返回发送的字节数。
    • 失败:返回-1。

7. 接收数据

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • 参数:

    • sockfd:套接字的文件描述符。
    • buf:用于接收数据的缓冲区。
    • len:要接收的数据的长度。
    • flags:接收标志,通常为0。
  • 返回值:

    • 成功:返回接收的字节数。
    • 失败:返回-1。

8.关闭套接字

int close(int sockfd);
  • 参数:

    • sockfd:套接字的文件描述符。
  • 返回值:

    • 成功:0,失败:返回-1。

服务器端通信流程 

1.创建套接字: 使用 socket 函数创建一个套接字,指定协议族(通常是 AF_INET 表示IPv4)、套接字类型(SOCK_STREAM 表示TCP流套接字)、协议(通常为0,表示自动选择协议)。

int server_socket = socket(AF_INET, SOCK_STREAM, 0);

2.绑定地址: 使用 bind 函数将套接字与特定的IP地址和端口号绑定。

struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8888);
server_address.sin_addr.s_addr = INADDR_ANY;bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address));

3.监听连接请求: 使用 listen 函数开始监听连接请求。

listen(server_socket, 5);  // 允许最多5个连接请求排队

4.接受连接: 使用 accept 函数接受客户端的连接请求,该函数会阻塞程序直到有客户端连接进来。

int client_socket = accept(server_socket, NULL, NULL);

5.进行数据交互: 使用 sendrecv 函数进行数据的发送和接收。

char buffer[1024];
recv(client_socket, buffer, sizeof(buffer), 0);
send(client_socket, "Hello from server", strlen("Hello from server"), 0);

6.关闭套接字: 使用 close 函数关闭服务端的套接字。

close(server_socket);

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>int main()
{// 1.创建监听的套接字int fd = socket(AF_INET, SOCK_STREAM, 0);if (fd == -1){perror("socket");return -1;}// 2.绑定本地的IP portstruct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);saddr.sin_addr.s_addr = INADDR_ANY; // INADD_ANY自动读取本地的ip地址int ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));if (ret == -1){perror("bind");return -1;}// 3.设置监听ret = listen(fd, 128);if (ret == -1){perror("listen");return -1;}// 4.阻塞并等待客户端的连接struct sockaddr_in caddr;int addrlen = sizeof(caddr);int cfd = accept(fd, (struct sockaddr *)&caddr, &addrlen);if (cfd == -1){perror("accept");return -1;}// 连接建立成功,打印客户端的ip和端口信息char ip[32];printf("客户端的ip:%s,端口:%d\n", inet_ntop(AF_INET, &caddr.sin_addr.s_addr, ip, sizeof(ip)), ntohs(caddr.sin_port));// 5.通信while (1){ // 接受数据char buff[1024];int len = recv(cfd, buff, sizeof(buff), 0);if (len > 0){printf("client say:%s\n", buff);send(cfd, buff, len, 0);}else if (len == 0){printf("客户端已经断开了连接...\n");break;}else{perror("recv");break;}}close(fd);return 0;
}

客户端通信流程

1.创建套接字: 使用 socket 函数创建一个套接字。

int client_socket = socket(AF_INET, SOCK_STREAM, 0);

2.设置服务器地址: 设置服务器的地址信息,包括协议族、IP地址和端口号。

struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8888);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");

3.连接服务器: 使用 connect 函数连接到服务器。

connect(client_socket, (struct sockaddr *)&server_address, sizeof(server_address));

4.进行数据交互: 使用 sendrecv 函数进行数据的发送和接收。

char buffer[1024];
send(client_socket, "Hello from client", strlen("Hello from client"), 0);
recv(client_socket, buffer, sizeof(buffer), 0);

5.关闭套接字: 使用 close 函数关闭客户端的套接字。

close(client_socket);

代码示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>int main()
{// 1.创建通信的套接字int fd = socket(AF_INET, SOCK_STREAM, 0);if (fd == -1){perror("socket");return -1;}// 2.连接服务器的IP portstruct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);inet_pton(AF_INET, "192.168.3.128", &saddr.sin_addr.s_addr);int ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));if (ret == -1){perror("connect");return -1;}int number = 0;// 3.通信while (1){ // 发送数据char buff[1024];sprintf(buff, "你好,hello,world,%d...\n", number++);send(fd, buff, sizeof(buff), 0);// 接收数据memset(buff, 0, sizeof(buff));int len = recv(fd, buff, sizeof(buff), 0);if (len > 0){printf("server say:%s\n", buff);}else if (len == 0){printf("服务器端已经断开了连接...\n");break;}else{perror("recv");break;}sleep(1);}// 关闭文件描述符close(fd);return 0;
}

相关文章:

102.套接字-Socket网络编程4(TCP通信流程)

目录 TCP编程流程 套接字函数 1.创建套接字 2.绑定地址 3.监听连接请求 4.接受连接 5. 连接到服务器 6. 发送数据 7. 接收数据 8.关闭套接字 服务器端通信流程 示例代码 客户端通信流程 代码示例 TCP编程流程 TCP是一个面向连接的&#xff0c;安全的&#xff0c;流…...

spring boot 2 升级到 spring boot 3 后文件上传失败

背景 项目需要&#xff0c;要求升级 spring boot 2.7 到 spring boot 3.2&#xff0c;升级过程中发现很多不兼容问题&#xff0c;下面说明文件上传失败的解决方案。 问题 spring boot 2 中不需要额外的配置&#xff0c;直接在 Controller 中配置 MultipartFile 接收页面传的…...

Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异,并取出不同的对象

Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异&#xff0c;并取出不同的对象。这可以通过使用 distinct() 和 filter() 方法来实现。 假设我们有两个 List&#xff0c;一个是 list1&#xff0c;另一个是 list2&#xff0c;我们想找出 list1 中存在但 list2…...

C语言还会存在多久

一、C语言的生命力 在当前的科技发展和就业市场需求下&#xff0c;可以肯定地说C语言并没有像一些新兴语言&#xff08;如Python、JavaScript等&#xff09;那样受到大量的关注。然而&#xff0c;并不意味着学习C语言的人会越来越少。 首先&#xff0c;C语言作为一种深受尊重…...

手持式安卓主板_PDA安卓板_智能手持终端方案

手持式安卓主板方案是一种智能终端设备&#xff0c;具备自动对焦和闪光灯功能&#xff0c;可以在昏暗的环境下快速扫描二维码并轻松采集数据。该方案还提供多渠道支付和数据采集功能&#xff0c;为用户提供了便捷的体验。 该方案的产品基于手持式安卓主板&#xff0c;并搭载了八…...

LeetCode103. Binary Tree Zigzag Level Order Traversal

文章目录 一、题目二、题解 一、题目 Given the root of a binary tree, return the zigzag level order traversal of its nodes’ values. (i.e., from left to right, then right to left for the next level and alternate between). Example 1: Input: root [3,9,20,n…...

PHP 判断给定两个时间是否在同一周,月,年

判断是否在同一周 date_default_timezone_set(PRC); //判断是否在同一周&#xff0c;原理&#xff1a;求出其中一个时间戳所在周的周一凌晨时间戳和周日24.00时间戳&#xff0c;如果另一个时间戳在这个范围内&#xff0c;则说明在同一周&#xff0c;否则不在同一周 function g…...

单机无锁线程安全队列-Disruptor

Disruptor 1、基本介绍 说到队列&#xff0c;除了常见的mq中间件&#xff0c;java中也自带线程安全的BlockingQueue&#xff0c;但是BlockingQueue通过在入队和出队时加锁的方式避免并发操作&#xff0c;性能上会大打折扣。 而Disruptor是一个线程安全、低延迟、吞吐量高的队…...

好工具知多少:国内外最常用的SCADA软件

随着现代SCADA系统的发展&#xff0c;工业自动化取得了巨大的飞跃。如今&#xff0c;监控和数据采集&#xff08;SCADA&#xff09;系统已成为工业过程的重要组成部分。这些系统使操作员能够实时监控和控制复杂的系统。 SCADA系统正在广泛的行业中发挥着至关重要的作用&#x…...

SQL Server 2016(创建数据库)

1、实验环境。 某公司有一台已经安装了SQL Server 2016的服务器&#xff0c;现在需要新建数据库。 2、需求描述。 创建一个名为"db_class"的数据库&#xff0c;数据文件和日志文件初始大小设置为10MB&#xff0c;启用自动增长&#xff0c;数据库文件存放路径为C:\db…...

Vue学习计划--Vue2(一)简单了解vue

Vue2的终止支持时间为2023年12月31日。 在这个矛盾的时间点&#xff0c;还是决定先把vue2的笔记放出来&#xff0c;在Vue2完结后再把Vue3的笔记补上。这样呢&#xff0c;2和3都不落下&#xff0c;也算是来一个启承的作用吧。在工作中呢&#xff0c;旧的项目可以维护&#xff0c…...

微信小程序生成二维码并保存到本地方法

微信小程序生成二维码请保存到本地方法 官方weapp-qrcode插件 github链接 功能完成样子 wxml <view class"qrcode"><canvas style"width: 275px; height: 275px;" canvas-idmyQrcode></canvas> </view> <view class" …...

shell_exec 和 exec区别

shell_exec 和 exec 都是用于在 PHP 中执行系统命令的函数&#xff0c;但它们之间有一些区别。 返回值类型&#xff1a;shell_exec 函数返回命令的输出结果作为字符串&#xff0c;而 exec 函数将输出结果存储在数组中。 输出结果&#xff1a;shell_exec 函数返回命令的完整输出…...

WPF创建进度条

使用wpf做一个原生的进度条&#xff0c;进度条上面有值&#xff0c;先看效果。 功能就是点击按钮&#xff0c;后台处理数据&#xff0c;前台显示处理数据的变化&#xff0c;当然还可以对进度条进行美化和关闭的操作&#xff0c;等待后台处理完毕数据&#xff0c;然后自动关闭。…...

全网最新最全面的Appium自动化:Appium常用操作之混合应用webview页面操作--待补充!

上下文操作&#xff1a; 在appium中&#xff0c;对于混合应用&#xff0c;需要进行WebView页面和原生应用的切换 常用的方法如下&#xff1a; 1、context(self) / current_context(self)&#xff1a;返回当前会话的当前上下文&#xff0c;context可以理解为可进入的窗口。对于…...

基于OpenCV+YOLOv5实现车辆跟踪与计数(附源码)

导 读 本文主要介绍基于OpenCVYOLOv5实现车辆跟踪与计数的应用&#xff0c;并给出源码。 资源下载 基础代码和视频下载地址&#xff1a; https://github.com/freedomwebtech/win11vehiclecount main.py代码:​​​​​​​ import cv2import torchimport numpy as npfrom tr…...

05、pytest断言确定的异常

官方用例 # content of test_sysexit.py import pytestdef f():raise SystemExit(1)def test_mytest():with pytest.raises(SystemExit):f()解读与实操 ​ 标准python raise函数可产生异常。pytest.raises可以断言某个异常会发现。异常发生了&#xff0c;用例执行成功&#x…...

金蝶云星空单据编辑界面,不允许批量填充操作

文章目录 金蝶云星空单据编辑界面&#xff0c;不允许批量填充操作案例演示开发设计测试 金蝶云星空单据编辑界面&#xff0c;不允许批量填充操作 案例演示 售后单&#xff0c;明细信息单据体&#xff0c;物料编码字段禁止批量填充。 开发设计 编写表单插件&#xff0c;在Be…...

Springboot项目启动成功后可通过五种方式继续执行

实现CommandLineRunner接口 项目初始化完毕后&#xff0c;才会调用方法&#xff0c;提供服务 Component public class StartRunner implements CommandLineRunner {Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner&qu…...

什么是供应链金融分账系统?

一、供应链金融的重要性 供应链金融在很多行业都是要用到,比如在抖音,快手店铺的商家资金回笼,通常需要7-21天的回款周期,这对于商家的周转来说是一件很困难的事情,在供应链金融中&#xff0c;分账就扮演着至关重要的角色&#xff0c;不仅是金融流程中的一环&#xff0c;更是保…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

spring Security对RBAC及其ABAC的支持使用

RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型&#xff0c;它将权限分配给角色&#xff0c;再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...