C语言-TCP通信创建流程

TCP通信创建流程

1. 客户端创建TCP连接

在整个流程中, 主要涉及以下⼏个接⼝socket() : 创建套接字, 使⽤的套接字类型为流式套接字connect() : 连接服务器send() : 数据发送recv() : 数据接收

创建套接字

首先,我们需要创建套接字,套接字是通信的基础。我们可以通过 socket() 函数来创建套接字。

int socket(int domain, int type, int protocol);
参数:@domain地址族AF_UNIX, AF_LOCAL  本地通信,数据不仅过网卡AF_INET         IPV4 ineter⽹通信  AF_INET6        IPV6 ineter⽹通信AF_PACKET       网卡上的数据包通信....@ type使⽤协议类型SOCK_STREAM 流式套接字(TCP)SOCK_DGRAM 报⽂套接字(UDP)SOCK_RAW原始套接字: (IP,ICMP)......@protocol协议编号0 : 让系统⾃动识别IPPROTO_TCP : TCP协议IPPROTO_UDP : UDP协议返回值:成功返回得到的⽂件描述符。当前可使用的最小描述符失败返回 -1

连接服务器

创建套接字之后,我们需要连接服务器。连接服务器需要调用 connect() 函数。

发起对套接字的连接 (基于⾯向连接的协议)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:@sockfd套接字描述符@addr   连接的套接字的地址结构对象的地址 (⼀般为服务器)服务器地址struct sockaddr {unsigned short sa_family; // 地址族 对应socket()中的domainchar sa_data[14]; // 地址数据 ip地址端口信息};struct sockaddr_in { short int sin_family; // 地址族 AF_INETunsigned short int sin_port; // 端口号struct in_addr sin_addr;// IP地址unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr};struct in_addr {uint32_t       s_addr; // IP地址};@addrlen地址长度返回值:成功返回0失败返回-1 并设置 errno

数据发送

连接服务器之后,我们就可以向服务器发送数据。发送数据需要调用 send() 函数。

基于套接字(建⽴连接)发送数据
int send(int sockfd, const void *buf, size_t len, int flags);
参数:@sockfd套接字描述符@buf    发送的数据@len    发送数据的长度@flags  发送标志
函数返回值:成功返回发送的字节数失败返回-1,并设置errno

数据接收

服务器向客户端发送数据之后,客户端就可以接收数据。接收数据需要调用 recv() 函数。

接收套接字的数据 (基于⾯向连接的协议)
int recv(int sockfd, void *buf, size_t len, int flags);
参数:@sockfd套接字描述符@buf    接收的数据@len    接收数据的长度@flags  接收标志
函数返回值:成功返回接收的字节数失败返回-1,并设置errno

完整流程

//todo tcp客户端,循环发送数据,接收回传数据
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>#define N 128
//初始化socket
int  init_socket(char *ip,char *port){int init_socket_fd= socket(AF_INET,SOCK_STREAM,0);if (init_socket_fd==-1){printf("init_socket err");exit(EXIT_FAILURE);}struct sockaddr_in server_addr;socklen_t len=sizeof(server_addr);bzero(&server_addr,len);server_addr.sin_family=AF_INET;inet_aton(ip,&server_addr.sin_addr);server_addr.sin_port= htons(atoi(port));//连接int ret= connect(init_socket_fd,(struct sockaddr*)&server_addr,len);if (ret==-1){printf("connect error,连接失败\n");exit(EXIT_FAILURE);}return init_socket_fd;
}//客户端接收数据
int Client_Receive_data(int socket_fd){char receive_msg[N];bzero(receive_msg,N);int recv_len= recv(socket_fd, receive_msg,sizeof(receive_msg),0);if (recv_len == -1) {printf("recv error\n");exit(EXIT_FAILURE);}receive_msg[recv_len] = '\0';printf("收到客户端数据:[%s]\n",receive_msg);
}//客户端发送数据
int  Client_Send_data(int socket_fd){char msg[N];while (1){bzero(&msg, sizeof (msg));printf("请输入:\n");fgets(msg, sizeof(msg),stdin);msg[strlen(msg)-1]='\0';printf("发送数据%s\n",msg);int  Send_data_len= send(socket_fd,&msg, strlen(msg),0);if (Send_data_len==-1){printf("发送失败 send err\n");exit(EXIT_FAILURE);}printf("发送了%d个字节\n",Send_data_len);if (strncmp(msg, "exit", 4) == 0) {printf("退出通信\n");close(socket_fd);break;}break;//接收Client_Receive_data(socket_fd);}return 0;
}int main(){//初始化连接int socket_fd = init_socket("172.17.128.1","8888");//发送数据Client_Send_data(socket_fd);return 0;
}

服务端流程

在这里插入图片描述

在上述流程中,相对于客户端主要增加以下新的流程
bind : 绑定 ip 地址与端⼝号,⽤于客户端连接服务器
listen : 建⽴监听队列,并设置套接字的状态为 listen 状态, 表示可以接收连接请求
accept : 接受连接, 建⽴三次握⼿, 并创建新的⽂件描述符, ⽤于数据传输

socket 套接字状态如下图:
在这里插入图片描述

CLOSED : 关闭状态
SYN-SENT : 套接字正在试图主动建⽴连接 [发送 SYN 后还没有收到 ACK],很短暂
SYN-RECEIVE : 正在处于连接的初始同步状态 [收到对⽅的 SYN,但还没收到⾃⼰发过去的SYN 的 ACK]
ESTABLISHED : 连接已建⽴

bind 函数 绑定 ip 地址与端⼝号,

函数头文件:
#include <sys/types.h>
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);函数功能:
绑定 ip 地址与端⼝号, 使得套接字可以接收客户端的连接请求参数:
sockfd : 套接字描述符
addr : 指向 sockaddr 结构体的指针, 包含了要绑定的 ip 地址和端⼝号
addrlen : 结构体 sockaddr 的长度返回值:
成功 : 0
失败 : -1, 并设置 errno 变量

在服务器绑定 ip 地址与端⼝号之后, 则需要让服务器 socket 套接字设置成被动监听状态,并
创建监听队列,这⾥需要调⽤ listen 函数

listen 函数 建⽴监听队列

函数头文件:
#include <sys/types.h>
#include <sys/socket.h>int listen(int sockfd, int backlog);函数功能:
建⽴监听队列, 并设置套接字的状态为 listen 状态, 表示可以接收连接请求参数:
sockfd : 套接字描述符
backlog : 监听队列的最大长度返回值:
成功 : 0
失败 : -1, 并设置 errno 变量

在服务器端调用 listen 函数之后, 则可以开始接收客户端的连接请求, 并创建新的套接字
用于数据传输, 这⾥需要调⽤ accept 函数

accept 函数 接受连接, 建⽴三次握⼿, 并创建新的⽂件描述符, ⽤于数据传输

函数头文件:
#include <sys/types.h>
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);函数功能:
接受连接, 建⽴三次握⼿, 并创建新的⽂件描述符, ⽤于数据传输参数:
sockfd : 套接字描述符
addr : 指向 sockaddr 结构体的指针, 用于返回客户端的 ip 地址和端⼝号
addrlen : 指向 socklen_t 类型的指针, 用于返回 sockaddr 结构体的长度返回值:
成功 : 新的套接字描述符
失败 : -1, 并设置 errno 变量

在服务器端调用 accept 函数之后, 则可以接收客户端的连接请求, 并创建新的套接字用于数据
传输, 调⽤ recv 和 send 函数进行数据传输

// todo TCP服务端程序 循环接收客户端数据,将数据回传
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>#define N 128//初始化socket
int  init_socket(char *ip,char *port){int init_socket_fd= socket(AF_INET,SOCK_STREAM,0);if (init_socket_fd==-1){printf("init_socket err");exit(EXIT_FAILURE);}struct sockaddr_in server_addr;socklen_t len=sizeof(server_addr);bzero(&server_addr,len);server_addr.sin_family=AF_INET;inet_aton(ip,&server_addr.sin_addr);server_addr.sin_port= htons(atoi(port));int bind_ret= bind(init_socket_fd,(struct sockaddr*)&server_addr,len);if (bind_ret == -1) {printf("bind error\n");exit(EXIT_FAILURE);}int listen_ret= listen(init_socket_fd,10);if (listen_ret == -1) {printf("listen error\n");exit(EXIT_FAILURE);}return init_socket_fd;
}//客户端发送消息
int  Server_Send_data(int clientFD,char* msg){strcat(msg,"-回传");int server_send_len=send(clientFD,msg,strlen(msg),0);if (server_send_len == -1) {printf("send error\n");exit(EXIT_FAILURE);}if (server_send_len == 0) {printf("客户端关闭连接\n");return -1;}printf("发送给客户端数据:[%s]\n",msg);return 0;
}//接收数据
int Server_Receive_data(int clientFD){while (1){//接收-使用新的文件描述符char recv_buf[N];bzero(recv_buf, sizeof(recv_buf));int recv_len = recv(clientFD, recv_buf, sizeof(recv_buf), 0);if (recv_len == -1) {printf("recv error\n");exit(EXIT_FAILURE);}if (recv_len == 0) {printf("客户端关闭连接\n");break;}if (strncmp(recv_buf, "exit", 4) == 0) {printf("客户端退出通信\n");close(clientFD);break;}printf("收到客户端消息:|%s|\n",recv_buf);Server_Send_data(clientFD, recv_buf);}return 0;
}int main(){int socket_fd = init_socket("172.17.140.183","8080");struct sockaddr_in cli_addr;socklen_t cli_len=sizeof(cli_addr);//获取客户端连接int clientFD= accept(socket_fd,(struct sockaddr*)&cli_addr,&cli_len);if (clientFD == -1){printf("accept error\n");exit(EXIT_FAILURE);}printf("连接 ip:%s, port:%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));//接收数据Server_Receive_data(clientFD);//关闭连接close(clientFD);
}

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

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

相关文章

在 ArkTS 中集成 C 语言模块来管理文件描述符

文章目录 前言ArkTS模块C语言模块C模块代码 总结 前言 在现代开发中&#xff0c;尤其是在处理文件操作时&#xff0c;使用文件描述符&#xff08;fd&#xff09;是一种常见的方法。ArkTS提供了一种强大的方式来与底层C代码交互&#xff0c;使我们能够利用C语言的性能优势来管理…

C++:平衡搜索二叉树(AVL)

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;平衡搜索二叉树&#xff08;AVL&#xff09;》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 文章目录 :maple_leaf:AVL树:maple_leaf:…

CeoMax总裁主题最新3.8.1破解免授权版/WordPress付费资源素材下载主题

CeoMax总裁主题最新3.8.1破解免授权版&#xff0c;一套WordPress付费资源素材下载的主题&#xff0c;感觉这是做资源站唯一一个可以和ripro媲美甚至超越的模板&#xff0c;UI很美&#xff0c;功能也很强大&#xff0c;有想学习的可下载搭建学习一下&#xff0c;仅供学习研究借鉴…

活动报名小程序

#活动报名工具# # 活动报名小程序 ## 项目简介 一款通用的活动报名工具&#xff0c;包含活动展示&#xff0c;微信支付&#xff0c;订单管理&#xff0c;分享评价等功能。 品客聚精彩&#xff0c;有你才精彩&#xff01;不只有线下活动还可以进行线上裂变活动。 …

Vue.js 2 项目实战(五):水果购物车

前言 Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它的设计目标是通过采用易于上手的结构和强大的功能&#xff0c;使前端开发变得更加简便和高效。以下是 Vue.js 的一些关键特性和优点&#xff1a; 核心特性 声明式渲染 Vue.js 使用声明式语法来描述用户界面&a…

OpenAI深夜丢炸弹硬杠谷歌搜索

这几年科技变革太快&#xff0c;AI更是飞速发展&#xff0c;作为一名IT老兵&#xff0c;使用过的搜索引擎也是一换再换。这不&#xff0c;刚消停了一段时间的OpenAI又丢出一个炸弹SearchGPT&#xff0c;直接跟谷歌掀桌子了。 1、谷歌搜索的无奈 早年只能用用百度搜索或者其余…

C++学习:C++是如何运行的

C 是一种强类型的编程语言&#xff0c;支持面向对象、泛型和低级内存操作。它的工作机制包括从编写源代码到生成可执行文件的一系列步骤。C与文件无关&#xff0c;文件只是容纳运行内容的载体&#xff0c;需要对文件以目标系统的规则编译后&#xff0c;才能在目标系统中运行。 …

JAVA SE 类和对象

类和对象 类定义和使用类的定义格式 类的实例化什么是实例化 this 引用this引用的特性 对象的构造及初始化如何初始化对象构造方法概念特性 在这里插入图片描述 **注意**&#xff1a; 封装封装的概念封装扩展之包导入包中的类自定义包包的访问权限控制举例 static成员static修饰…

微信小游戏之 三消(一)

首先设定一下 单个 方块 cell 类&#xff1a; 类定义和属性 init 方法 用于初始化方块&#xff0c;接收游戏实例、数据、宽度、道具类型和位置。 onWarning 方法 设置警告精灵的帧&#xff0c;并播放闪烁动作&#xff0c;用于显示方块的警告状态。 grow 方法 根据传入的方向…

磨煤机加载油站系统比例阀放大器

磨煤机液压系统是火力发电厂中不可或缺的重要组成部分&#xff0c;它主要负责为磨煤机提供并调节必须的碾磨压力。这一系统的核心功能是通过BEUEC比例放大器配套比例溢流阀精确控制&#xff0c;以适应煤炭处理过程中对压力的不同需求&#xff0c;确保煤炭的有效碾磨及火力发电的…

C语言 | Leetcode C语言题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; int hIndex(int* citations, int citationsSize) {int left 0, right citationsSize - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > citationsSize - mid) {right mid - 1;} else {left mi…

Jenkins持续集成软件

1.什么是jenkins? jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;提供一个开放易用的软件平台&#xff0c;时软件项目可以进行持续集成。 通俗来说&#xff1a;Jenkins软件就是自动拉取git远程仓库所…

Java 面试相关问题(下)——JVM相关问题GC相关问题

1. 类加载1.1 类的生命周期说一下&#xff1f;1.2 介绍下生命周期中的加载&#xff1f;1.3 介绍下生命周期中的验证&#xff1f;1.4 介绍下生命周期中的准备&#xff1f;1.5 介绍下生命周期中的解析&#xff1f;1.6 介绍下生命周期中的初始化&#xff1f;1.7 介绍下生命周期中的…

秋叶大神中文版Stable Diffusion下载安装使用教程

Stable Diffusion是什么&#xff1f; Stable Diffusion是一款开源的AI绘画软件&#xff0c;于2022年发布&#xff0c;由CompVis、Stability AI和LAION的研究人员创建。该软件具有出色的图像生成功能&#xff0c;使用户能够从头开始绘制作品&#xff0c;也可以使用现有的图像进…

花几千上万学习Java,真没必要!(三十)

异常&#xff1a; 测试测试代码1&#xff1a; package catchtest.com; public class TryCatchExample { //使用一个或多个 catch 块捕获并处理异常。public static void main(String[] args) { try { // 尝试执行的代码块 int result 10 / 0; // 引发 ArithmeticExceptio…

AI如何助力UI设计师互联网学习?

嘿&#xff0c;咱 UI 设计师想用互联网学习&#xff0c;可真不容易&#xff01;资料筛选难&#xff0c;学习资源杂&#xff0c;真让人头疼。不过还好有 AI 工具能帮忙&#xff0c;提效率&#xff01; 这一年多来&#xff0c;我在 ai123.cn 这个平台上&#xff0c;可算是找到了…

【LeetCode、牛客】链表分割、链表的回文结构、160.相交链表

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构 &#x1f4da;本系列文章为个人学…

Web网页端IM产品RainbowChat-Web的v7.1版已发布

一、关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统&#xff0c;是RainbowChat的姊妹系统&#xff08;RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址) 的产品级移动端IM系统&#xff09;。 ► 详细介绍&#xff1a;http://www.52im.net/thread-2…

WEB前端11-Vue2基础01(项目构建/目录解析/基础案例)

Vue2基础(01) 1.Vue2项目构建 步骤一&#xff1a;安装前端脚手架 npm install -g vue/cli步骤二&#xff1a;创建项目 vue ui步骤三&#xff1a;运行项目 npm run serve步骤四&#xff1a;修改vue相关的属性 DevServer | webpack //修改端口和添加代理 const { defineCo…