【Linux网络编程(五)】TCP编程流程

2023-05-16

文章目录

  • TCP编程
    • 1 TCP介绍、编程流程
    • 2 TCP C/S架构
    • 3 TCP客户端编程流程
      • 1. 创建TCP套接字
      • 2. connect连接服务器
      • 3. send发送请求
      • 4 recv接收应答 (默认带阻塞)
      • 5 close
      • 6 客户端编程流程代码
    • 4 TCP服务端编程流程
      • 1. 创建TCP套接字
      • 2. bind 给服务器绑定固定的port、IP地址信息
      • 3. listen 监听并创建队列
      • 4. accept 提取客户端的连接(阻塞)
      • 5. send 发送消息到客户端
      • 6. recv 接收客户端的消息
      • 7. close关闭所有套接字
      • 8. TCP服务端编程流程代码

TCP编程

1 TCP介绍、编程流程

1、面向连接的流式协议;可靠、出错重传、且每收到一个数据都要给出相应的确认
2、通信之前需要建立链接
3、服务器被动链接,客户端是主动链接

在这里插入图片描述



2 TCP C/S架构

在这里插入图片描述



3 TCP客户端编程流程

  1. socket 创建套接字
  2. connect 连接服务器
  3. send 发送请求
  4. recv 接收应答
  5. close

1. 创建TCP套接字

socket创建的套接字:没有端口、主动连接别人

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

注:TCP是SOCK_STREAM, UDP为SOCK_DGRAM

2. connect连接服务器

如果sockfd没有被bind绑定,第一次调用connect系统自动分配随机端口,后续使用该端口

int connect(int socket, const struct sockaddr *address, socklen_t address_len)
/*
socket: 套接字
address: 连接的服务器地址结构
address_len: 地址结构长度
*/

注:如果客户端和服务器通信,必须使用connect事先建立连接

3. send发送请求

ssize_t send(int socket, const void *buffer, size_t length, int flags)
/*
socket: 客户端套接字
buffer:发送的消息
length:消息长度
flags: 0

返回值:
	成功:返回发送的字节数
	失败:返回-1
*/

4 recv接收应答 (默认带阻塞)

ssize_t recv(int socket, void *buffer, size_t length, int flags);
/*
socket: 客户端套接字
buffer: 接收的消息
length:能接收的最大长度
flags:0

返回值:
	成功:成功接收的字节数
	失败:-1
*/

5 close

#include <unistd.h>

int close(int fildes);

6 客户端编程流程代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char const *argv[])
{
	//创建tcp套接字 SOCK_STREAN
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
	//connect连接服务器(知道服务器地址信息)
	struct sockaddr_in ser_addr;
	bzero(&ser_addr, sizeof(ser_addr));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(8000);
	ser_addr.sin_addr.s_addr = inet_addr("10.9.21.211");
	connect(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));

	//客户端发送请求
	send(sockfd, "hello tcp", strlen("hello tcp"), 0 );
	
	//客户端接收服务器的应答
	unsigned char buf[1500] = "";
	int len = recv(sockfd, buf, sizeof(buf), 0);
	printf("服务器的应答:%s\n", buf);
	
	//关闭套接字
	close(sockfd);
	
	return 0;
}


4 TCP服务端编程流程

  1. socket 创建套接字
  2. bind 绑定固定的port、ip地址信息
  3. listen 监听套接字 创建连接队列
  4. accept
  5. send 发送请求
  6. recv 接收应答
  7. close

1. 创建TCP套接字

socket创建的套接字

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

注:TCP是SOCK_STREAM, UDP为SOCK_DGRAM

2. bind 给服务器绑定固定的port、IP地址信息

struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr)):
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(8000);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)):

3. listen 监听并创建队列

listen监听:等待客户端的连接到来,经过三次握手(底层自动),将客户端放入入连接队列

#include <sys/socket.h>

int listen(int socket, int backlog);

/*
功能:
	1. 将监听套接字由主动变被动
	2. 为该套接字创建连接队列

参数:
	socket:变被动的套接字
	backlog:连接队列的大小

返回值:
	成功:0
	失败:-1
*/

4. accept 提取客户端的连接(阻塞)

#include <sys/socket.h>

int accept(int sockfd,struct sockaddr *cliaddr, socklen_t *addrlen);

/*
功能:
	从已连接队列中取出一个已经建立的连接,如果没有任何连接可用,则进入睡眠等待(阻塞)

参数:
	sockfd: socket监听套接字
	cliaddr: 用于存放客户端套接字地址结构
	addrlen:套接字地址结构体长度的地址

返回值:
	已连接套接字
*/

注:返回的是一个已连接套接字,服务器只能通过已连接套接字和客户端进行数据通信
在这里插入图片描述

5. send 发送消息到客户端

ssize_t send(int socket, const void *buffer, size_t length, int flags)
/*
socket: 客户端套接字
buffer:发送的消息
length:消息长度
flags: 0

返回值:
	成功:返回发送的字节数
	失败:返回-1
*/

注:如果ssize_t>0,表示发送成功(实际发送的字节数)
  如果ssize_t为-1,表示发送是失败
  tcp不允许send发送0长度报文(服务端接收0长度报文则为客户端断开连接)
  udp允许sendto发送0长度报文

6. recv 接收客户端的消息

ssize_t recv(int socket, void *buffer, size_t length, int flags);
/*
socket: 客户端套接字
buffer: 接收的消息
length:能接收的最大长度
flags:0

返回值:
	成功:成功接收的字节数
	失败:-1
*/

注:如果ssize_t为0,表示客户端已经断开连接
  如果ssize_t>0,表示recv收到的实际字节数
  如果ssize_t为-1,表示recv读取数据出错

7. close关闭所有套接字

#include <unistd.h>

int close(套接字);

注:close后会导致对方recv收到0长度报文

8. TCP服务端编程流程代码

#include <stdio.h>
#include <sys/socket.h> //socket
#include <netinet/in.h> //struct sockaddr_in
#include <string.h>     //memset
#include <arpa/inet.h>  //htos
#include <unistd.h>     //close

int main()
{
    //创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd < 0)
	{
		perror("cockt");
		return 0;
	}
    
    //bind绑定固定的port、ip地址信息
    struct sockaddr_in my_addr;
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(9000);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
	if(ret == -1)
	{
		perror("bind");
		return 0;
	}
	//监听套接字 创捷连接队列
	ret = listen(sockfd, 10);
	if(ret == -1)
	{
		perror("listen");
		return 0;
	}
	
	//提取客户端的连接
	while(1)
	{
		//一次只能提取一个客户端
		struct sockaddr_in cli_addr;
		socklen_t cli_len = sizeof(cli_addr);
		int cfd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len);
		if(cfd < 0 ) //提取失败
		{
			perrer("accept\n");
			break;
		}
		else
		{
			char ip[16] = "";
			unsigned short port = 0;
			inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, ip, 16);
			port = ntohs(cli_addr.sin_port);
			//打印客户端的信息
			printf("客户端:%s %d connected\n", ip, port);
			
			while(1)
			{
				//获取客户端的请求
				unsigned char buf[1500] = "";
				int len = recv(cfd, buf, sizeof(buf), 0);
				if(len == 0) //客户端已经关闭
				{
					//关闭与客户端连接的套接字
					close(cfd);
					break;
				}
			
				//应答客户端
				send(cfd, buf, len, 0);
			}
		}	
	}
	
	//关闭监听套接字
	close(sockfd);
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux网络编程(五)】TCP编程流程 的相关文章

  • centos6.5vim基本配置

    简单的vim配置 xff1a 在目录 etc 下面 xff0c 有个名为vimrc的文件 xff0c 这是系统中公共的vim配置文件 xff0c 对所有用户都有效 而在每个用户的主目录下 xff0c 都可以自己建立私有的配置文件 xff0c
  • atexit注册函数

    函数名 atexit 头文件 include lt stdlib h gt 功 能 注册终止函数 即main执行结束后调用的函数 用 法 int atexit void func void 注意 xff1a 按照ISO C的规定 xff0c
  • Linux管道的容量大小及管道的数据结构

    一 管道容量 xff1a 我们通过ulimit a 命令查看到的pipo size定义的是内核管道缓冲区的大小 xff0c 这个值的大小是由内核设定的 xff1b 而pipe capacity指的是管道的最大值 xff0c 即容量 xff0
  • 线程初体验

    线程的概念 xff1a 线程是一个进程地址空间的一个控制流程 xff0c 是调度的基本单位 xff0c 由于同一进程的多个线程共享同一地址空间 因此Text Segment Data Segment都是共享的 如果定义一个函数 在各线程中都
  • 死锁的四个必要条件

    死锁产生的四个必要条件 互斥条件 xff1a 资源是独占的且排他使用 xff0c 进程互斥使用资源 xff0c 即任意时刻一个资源只能给一个进程使用 xff0c 其他进程若申请一个资源 xff0c 而该资源被另一进程占有时 xff0c 则申
  • 线程安全与可重入函数的区别

    线程安全 xff1a 一般来讲就是一个代码块被多个并发线程反复调用时会一直产生正确的结果 如何确保线程安全 xff1a 确保线程安全 主要 考虑线程之间共享变量的安全 xff0c 每个线程私有的内容包括 xff1a 线程id xff0c e
  • Linux模拟实现sleep

    工作原理 linux中的sleep函数能够让程序休眠一定的秒数 xff0c 到时间后自动恢复运行 实现思路 设定睡眠的秒数 睡眠 xff08 挂起 xff09 恢复运行实现机制 设定睡眠的秒数 xff1a 采用alarm 函数设定需要睡眠的
  • 基于ESP32C3处理器创建Hello World工程-并使用OpenOCD进行Debug

    1 编程环境 1 1 硬件 序号 名称 描述 备注 1 ESP C3 12F KIT 深圳安信可开发的基于其自家ESP C3 12F模块的开发板 淘宝购买 2 ESP Prog 乐鑫官方推出基于FT2232HL接口芯片的JTAG调试器 淘宝
  • 平衡二叉树旋转详解

    平衡二叉树的定义 xff08 AVL xff09 定义 平衡二叉树或者是一棵空树 xff0c 或者满足以下的性质 xff1a 它的左子树和右子树的高度之差的绝对值不超过1 xff0c 并且左子树和右子树也是一个平衡二叉树 平衡因子 左子树高
  • Linux进程组,作业,会话,作业控制详解

    进程组 xff08 1 xff09 每个进程除了有一个进程id之外还属于进程组 xff0c 进程组是一个或者多个进程的集合 xff0c 通常 xff0c 他们与同一作业相关联 xff0c 可以接收来自同一终端的各种信号 xff08 2 xf
  • 如何写一个linux精灵进程

    什么是精灵进程 精灵进程也称守护进程 xff08 Daemon xff09 xff1a 是运行在后台的一种特殊进程 xff0c 它独立于控制终端并周期性的执行某种任务 xff0c 或等待处理某些发生的事件 Linux大多数服务器就是用精灵进
  • TCP的四种定时器

    TCP使用的四种定时器 xff08 Timer xff09 重传计时器 xff08 Retransmission Timer xff09 坚持计时器 xff08 Persistent Timer xff09 保活计时器 xff08 keep
  • Linux进程池与线程池以及线程池的简单实现

    通过动态创建子进程 xff08 或者子线程 xff09 来实现并发服务器的 这样做有如下缺点 xff1a 1 动态创建进程 xff08 或线程 xff09 是比较耗费时间的 xff0c 这将导致较慢的客户响应 2 动态创建的子进程 xff0
  • linux下vim中多行注释和删除多行注释

    多行注释 xff1a a 按下Ctrl 43 v xff0c 进入列模式 b 在行首选择需要注释的行 c 按下 I xff0c 进入插入模式 xff1b d 然后输入注释符 xff08 等 xff09 e 按下 Esc 键 删除多行注释 x
  • socket编程以及select、epoll、poll示例详解

    socket编程 socket这个词可以表示很多概念 xff0c 在TCP IP协议中 IP地址 43 TCP或UDP端口号 唯一标识网络通讯中的一个进程 xff0c IP 43 端口号 就称为socket 在TCP协议中 xff0c 建立
  • 命令替换的两种方式$()和``

    命令替换的含义 命令替换是指将命令的输出作为命令替换的位置的文本 命令替换的一般作用是抽取一个命令的输出 然后使用 61 操作赋值到一个变量供以后使用 命令替换的两种方式 1 反引号 xff0c 电脑键盘Esc下面的那个键 使用如下图 xf
  • Linux中eval命令

    eval命令的作用 eval命令会首先扫描命令进行所有的替换 xff0c 然后在执行所有的命令 xff0c 该命令适用于那些一次扫描无法实现其功能的变量 xff0c 该命令对变量进行两次扫描 xff0c 这些需要进行两次扫描的变量被称为复杂
  • Shell脚本实现带颜色进度条

    最近刚刚学习啦shell脚本的编程方法 xff0c 就采用shell脚本实现了一个带颜色的进度条 xff0c 下面将结果展示给大家 程序结果 实现这个其实非常的简单 xff0c 只需要了解一些基本的语法就可以了 进度条的实现就是循环加输出格
  • KiCAD绘制原理图的几个常用的操作之一

    摘要 在绘制原理图的的过程中 xff0c 会用到很多的操作功能 xff0c 今天就介绍几个在绘制原理图时必须要用到的几个功能 xff1a 1 放置原理图符号 xff1b 2 放置电源符号 xff1b 3 绘制器件引脚之间的连线 xff1b
  • linux中crond服务与crontab用法详解

    crond服务 crond服务是一种守护进程 xff0c 用来定期执行程序 xff0c 安装完成系统之后 xff0c 默认便会启动此任务调度命令 crond命令每分钟会定期检查是否有要执行的工作 xff0c 如果有要执行的工作便会自动执行该

随机推荐

  • shell字符串截取方法

    运算符截取 1 和 截取字符串 xff08 删左边留右边 xff09 下面我们先看代码和运行结果 解释 xff1a span class hljs keyword var span span class hljs keyword strin
  • 面试题:判断一个节点是否在一棵二叉树中

    题目 xff1a 判断一个节点是否在一棵二叉树中 结点定义如下 span class hljs keyword struct span BinaryTree BinaryTree span class hljs keyword char s
  • shell脚本实现希尔(shell)排序

    题目 xff1a 采用shell脚本实现希尔排序 最近刚刚学习啦shell脚本编程 xff0c 因此写了一个简单的希尔排序 span class hljs shebang bin bash span arr 61 span class hl
  • Linux小项目-群聊系统

    项目名称 xff1a chat room群聊系统背景知识与主要技术 xff1a 熟悉Linux基本指令的使用 xff08 ls cd make mkdir top basename pwd cp mv rm touch xff09 熟悉li
  • 求先递增在递减数组中的最大值

    题目 xff1a 一个数组先从小到大递增在从大到小递减 xff0c 找出数组的最大值 思路 xff1a 可以依次遍历整个数组如果array i 满足array i gt array i 1 amp amp array i gt array
  • 哈希(HASH)冲突的处理方法

    通过构造良好的哈希函数可以减少冲突 xff0c 但一般不能完全避免冲突 因此解决冲突是哈希法的另一个关键问题 常用的解决冲突方法有以下四种 开放地址法 这种方法也称再散列法 xff0c 基本思想是当关键字key的哈希地址p 61 H key
  • 消息队列实现从一个进程向另一个进程发送一个数据块的方法

    首先是Comm h的代码 include lt stdio h gt include lt string h gt include lt sys types h gt include lt sys ipc h gt include lt s
  • 打开PADS出现“PADS已停止工作”提示的解决办法

    一 场景 前一天还可以正常使用 xff0c 今天处理完一些事务后点击PADS打算画一些PCB xff0c 结果弹窗出现 PADS已停止工作 xff0c 无论是打开PADS的Logic还是Layout文件都提示这个 xff0c 打开其他之前正
  • cmake解决动态库soname,rpath以及符号冲突解决方案备忘

    set target properties TGT PROPERTIES NO SONAME TRUE SKIP BUILD RPATH TRUE LINK OPTIONS 34 Wl version script 61 CMAKE CUR
  • KiCAD绘制原理图---------创建一个新的原理图符号

    1 创建一个新的原理图库文件 第1步 xff0c 打开原理图器件编辑界面 如图1 1 1所示 xff0c 点击 Smbol Editor 图标进入器件编辑界面 第2步 xff0c 进入文件管理菜单 如图1 2 1所示 xff0c 点击 Fi
  • ubuntu 查看内存命令

    Linux中使用free 可以查看系统内存使用状态 默认单位为KB 为单位 xff0c 在此我以MB为单位说明 lostman 64 lostman MS 6702E 桌面 free m total used free shared buf
  • Nvidia Xavier Nx平台SD卡热插拔检测失效问题调试记录

    1 前言 Xaiver NX上 使用sdmmc3为sd卡 正常工作 但是 当热插拔时会检测不到 使用GPIO12 GPIO3 PCC 04 作为cd gpio cd gpios lt amp tegra aon gpio TEGRA194
  • MobaXterm连接虚拟机超时:Connection timed out

    折腾了几个小时 来两句废话 1 首先我确认了虚拟机防火墙已关 2 ip配置无问题 3 重置VMware网络设置啥的 然而并没有卵用 4 虚拟机ping百度正常 主机ping虚拟机正常 以上4条依然无效 解决方案 原理不清楚 但是解决了 通过
  • Windows下python激活虚拟环境后仍然使用全局python和pip

    这么过分一定要发CSDN jpg 在windows下 xff0c 激活python虚拟环境后 xff0c 使用的python和pip仍然是全局的python和pip 如图 使用pip list 可以看到这个包这么多 xff0c 显然不是我刚
  • openmv 自学笔记(APRILTAG标记追踪)

    由图可知 id 为5 旋转角度 为11 0 左边旋转 角度增加 正式时候调度接近0 右边旋转 角度减少 由360度 向右减少 Tx 在左边的时候 为负数 右边为正值 Ty 在上边的时候为正数 左边为负值 Tz 从远处 到近处 由负数到向正数
  • 学习STM32(3)-电源、时钟、复位电路

    Stm32 时钟分析 该分析材料大部分来自opendev 论坛 xff0c 我所做的只不过是加上一些自己的分析和整理 xff0c 由于个人能力有限 xff0c 纰漏之处在所难免 xff0c 欢迎指正 一 硬件上的连接问题 如果使用内部RC振
  • 只是运行roslauch来发布一次TF

    如果只是希望运行roslaunch来发布一次TF xff0c 可以使用launch文件中的node标签来实现 下面是一个发布一次TF的launch文件例子 xff1a lt launch gt lt node pkg 61 34 tf2 r
  • 2019年年终总结(流水账)

    2019年年终总结 流水账 前言 马上就要是2020年了 xff0c 我此时敲下我的第一篇年终总结 马上就要过去的2019年对于我来说是平凡但却不平淡的一年 xff0c 这一年里我经历了很多 xff0c 虽然这些在别人眼中可能是微不足道的
  • 融资租赁与经营租赁的区别

    我现在手上项目的客户是一家销售公司 xff0c 他们有把自己的商品租赁给别的公司经营的业务 于是就有了上面的融资租赁与经营租赁 xff0c 这两种方式在财务上对资产的处理是不一样的 下面我们来看看这个场景 xff1a A公司把资产租给B公司
  • 【Linux网络编程(五)】TCP编程流程

    文章目录 TCP编程1 TCP介绍 编程流程2 TCP C S架构3 TCP客户端编程流程1 创建TCP套接字2 connect连接服务器3 send发送请求4 recv接收应答 xff08 默认带阻塞 xff09 5 close6 客户端