SOCKET编程和TCP通信案例三次握手四次挥手

文章目录

    • 一、SOCKET
    • 1、网络套接字SOCKET
    • 2、网络字节序
    • 2.1、小端法
    • 2.2、大端法
    • 2.3、字节序转换
    • 3、IP地址转换函数
    • 3.1、本地字节序转网络字节序
    • 3.1.1、函数原型:
    • 3.1.2、返回值
    • 3.2、网络字节序转本地字节序
    • 3.2.1、函数原型
    • 3.2.2、返回值
    • 4、sockaddr地址结构(服务器server写法)
    • 4.1、struct sockaddr_in addr
    • 4.2、struct sockaddr_in结构体
    • 5、socket模型创建流程分析
    • 6、socket和bind
    • 6.1、socket
    • 6.1.1、socket函数
    • 6.1.2、返回值
    • 6.2、bind
    • 6.2.1、bind函数
    • 7、listen和accept
    • 7.1、listen
    • 7.1.1函数原型
    • 7.1.2、返回值
    • 7.2、accept
    • 7.2.1、函数原型
    • 7.2.2、返回值:
    • 8、connect函数(client)
    • 8.1.1、函数原型
    • 8.1.2、返回值:
    • 二、TCP通信案例
    • 1、TCP通信模型
    • 1.1、需求分析
    • 1.2、功能简介
    • 2、步骤分析与代码
    • 2.1、server
    • 2.1.1、步骤分析
    • 2.1.2、server.c代码
    • 2.2、client
    • 2.2.1、步骤分析
    • 2.2.2、client.c代码
    • 三、三次握手 和四次挥手
    • 1、三次握手
    • 2、数据通信(三次握手之后)
    • 3、四次挥手(关闭连接)

一、SOCKET

1、网络套接字SOCKET

(1)一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现)
(2)在通信过程中,套接字一定是成对出现的
在这里插入图片描述

2、网络字节序

2.1、小端法

计算机本地存储,高位存高地址,低位存低地址

2.2、大端法

网络存储,高位存低地址,低位存高地址

2.3、字节序转换

为了能使计算机和网络之间能够顺利通信,需要进行字节序的转换,就是大小端之间的转换,l表示32位无符号整型,s表示16位短整型,h代表host主机,n代表net网络
(1)htonl—》本地—》网络(IP)
(2)htons—》本地—》网络(port端口号)
(3)ntohl—》网络—》本地(IP)
(4)ntohs—》网络—》本地(port)

3、IP地址转换函数

3.1、本地字节序转网络字节序

3.1.1、函数原型:

Int inet_pton(int af,const char*src,void *dst)//本地字节序(string IP)—》网络字节序	

(1)af:AF_INET、AF_INET6
(2)src:传入,IP地址(点分十进制)
(3)dst:传出,转换后的网络字节序的IP地址

3.1.2、返回值

成功:1
异常:0,说明src指向的不是一个有效的IP地址
失败:-1

3.2、网络字节序转本地字节序

3.2.1、函数原型

Const char *inet_ntop(int af,void *src,char *dst,socklen_t,size);//网络字节序—》本地字节序(string IP)

af:AF_INET、AF_INET6
src:网络字节序IP地址
dst:转换后的本地字节序字节序的IP地址(string IP)
size:dst的大小

3.2.2、返回值

成功:dst
失败:NULL

4、sockaddr地址结构(服务器server写法)

4.1、struct sockaddr_in addr

Addr.sin_family=AF_INET/AF_INET6
Addr.sin_port=htons(9527)Int dst;Inet_pton(AF_INET,192.168.22.54,(void*)&dst)
Addr.sin_addr.s_addr=dst
addr.sin_addr.s_addr=htonl(INADDR_ANY)//[重点]取出系统中有效的任意IP地址,二进制类型
Bind(fd,(sockaddr *)addr,size)

注意,这里sockaddr给bind传参的时候需要强转
在这里插入图片描述

4.2、struct sockaddr_in结构体

struct sockaddr_in {sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order */struct in_addr sin_addr; /* internet address */
};
/* Internet address.*/
struct in_addr {uint32_t s_addr;/* address in network byte order */
};

5、socket模型创建流程分析

一个客户端和一个服务器通信时,除了各自的一个套接字以外,还有一个监听套接字,一共是三个套接字
在这里插入图片描述

6、socket和bind

6.1、socket

6.1.1、socket函数

#include<sys/socket.h>
Int socket(int domin,int type,int protocol); //创建一个套接字

(1)Domin:AF_INET、AF_INET6、AF_UNIX(创建本地套接字时使用)
(2)Type:SOCK_STREAM(流式类型)、SOCK_DGRAM(报式类型)
(3)Protocol:0(前面的type有两个,这里的protocol代表的是对前面两种类型的选择,0代表SOCK_STREAM,代表协议是TCP,1代表的是SOCK_DGRAM,代表协议是UDP)

6.1.2、返回值

成功:新套接字所对应的文件描述符
失败:-1,设置errno

6.2、bind

6.2.1、bind函数

#include<arpa/inet.h>
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);//给socket绑定一个地址结构(IP+port)

(1)Sockfd:socket函数返回值
Struct sockaddr_in addr;
Addr.sin_family=AF_INET;
Addr.sin_port=htons(8888);
Addr.sin.s_addr=htonl(INADDR_ANY);//(服务器写法INADDR_ANY)
(2)Addr:(struct sockaddr *)&addr
Addrlen:sizeof(addr) 地址结构的大小
(3)返回值
成功:0
失败:-1 errno

7、listen和accept

7.1、listen

7.1.1函数原型

int listen(int sockfd,int backlog);//设置同时与服务器建立连接的上限数

(1)Sockfd:socket函数返回值
(2)Backlog:上限数值,最大值是128

7.1.2、返回值

成功:0
失败:-1 errno

7.2、accept

7.2.1、函数原型

int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);//阻塞等待客户端建立连接,成功的话,返回一个与客户端成功链接的socket文件描述符

(1)Sockfd:socket函数返回值
Addr:传出参数,成功与服务器建立连接的那个客户端的地址结构(IP+port)
(2)Socklen_t client_addr_len=sizeof(addr)
Addrlen:传入传出。&client_addr_len
入:addr的大小;出:客户端addr实际大小

7.2.2、返回值:

成功:能与服务器进行数据通信的socket对应的文件描述符
失败:-1,errno

8、connect函数(client)

8.1.1、函数原型

Int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);//使用现有的socket与服务器建立连接

(1)Sockfd:socket函数返回值
Struct sockaddr_in server_addr;//服务器地址结构
Server_addr.sin_family=AF_INET
Server_addr.sin_port=8087//跟服务器bind时设定的port完全一致
Server_adde.sin_addr.s_addr
Inet_pton(AF_INET,”服务器的Ip地址”,&server_addr.sin_addr.s_addr)
(2)Addr:传入参数,服务器的地址结构
(3)Addrlen:服务器的地址结构的长度

8.1.2、返回值:

成功:0
失败:-1
如果不使用bind绑定客户端地址结构,采用“隐式绑定”

二、TCP通信案例

1、TCP通信模型

1.1、需求分析

创建一个能从客户端输入10次HELLO,从服务端转换成10个hello的通信器。

1.2、功能简介

该通信器可以从客户端发送10条HELLO给服务端,服务端接收之后可以在屏幕上输出10个hello。

2、步骤分析与代码

2.1、server

2.1.1、步骤分析

(1)socket();//创建socket
(2)bind();//绑定服务器地址结构
(3)listen();//设置监听上限
(4)connect();//阻塞监听客户端连接
(5)read(fd);读socket获取客户端数据
(6)toupper();//数据处理
(7)write(fd);
(8)read(fd);
(9)close();

2.1.2、server.c代码

#include<stdio.h>                                                                #include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/socket.h>
#include<ctype.h>
#include<arpa/inet.h>#define SERVER_PORT 8087void sys_err(char*str)
{perror(str);exit(1);
}int main(int argc,char*argv[])
{int lfd=0,cfd=0;int ret,i;char buf[BUFSIZ],client_IP[1024]; int conter=10;struct sockaddr_in server_addr,client_addr;socklen_t client_addr_len;server_addr.sin_family=AF_INET;server_addr.sin_port=htons(SERVER_PORT);server_addr.sin_addr.s_addr=htonl(INADDR_ANY);lfd=socket(AF_INET,SOCK_STREAM,0);if(lfd==-1){sys_err("socket error");}bind(lfd,(struct sockaddr*)&server_addr,sizeof(server_addr));listen(lfd,128);client_addr_len=sizeof(client_addr);cfd=accept(lfd,(struct sockaddr *)&client_addr,&client_addr_len);if(cfd==-1){sys_err("accept error");}printf("client ip:%s port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),ntohs(client_addr.sin_port));while(--conter){ret=read(cfd,buf,sizeof(buf));write(STDOUT_FILENO,buf,ret);for(i=0;i<ret;i++){buf[i]=toupper(buf[i]);                                                    }write(cfd,buf,ret);}close(lfd);close(cfd);return 0;
}

2.2、client

2.2.1、步骤分析

(1)socket();创建socket
(2)connect();与服务器建立连接
(3)write();
(4)read();
(5)显示读取结果
(6)close();

2.2.2、client.c代码

#include<stdio.h>                                                                
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>#define SERVER_PORT 8087void sys_err(char*str)
{perror(str);exit(1);
}int main(int argc,char*argv[])
{int cfd;int conter=10;char buf[BUFSIZ];struct sockaddr_in server_addr;server_addr.sin_family=AF_INET;server_addr.sin_port=htons(SERVER_PORT);inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);cfd=socket(AF_INET,SOCK_STREAM,0);if(cfd==-1){sys_err("socket error");}int ret=connect(cfd,(struct sockaddr *)&server_addr,sizeof(server_addr));if(ret!=0){sys_err("connect error");}while(--conter)                                                                {write(cfd,"hello\n",6);ret=read(cfd,buf,sizeof(buf));write(STDOUT_FILENO,buf,ret);sleep(1);}close(cfd);return 0;
}   

三、三次握手 和四次挥手

1、三次握手

1、客户端发送一个STN标志位。500(0)表示的是发送一个包号为500,数据大小为0的数据包,从而告知服务器,我要与你建立连
2、此时服务器会回应一个ACK,表示我接收到了你的请求,501号包以前的数据我都收到了。服务器也会发送一个SYN标志位,告诉客户端,我要和你建立连接
3、客户端收到服务器的请求以后,也会回应一个ACK,表示请求收到了。三次连接的过程发生在内核。在用户层面的体现就是
accept (内核)和connect(用户)函数成功执行并返回了
在这里插入图片描述

2、数据通信(三次握手之后)

客户端发送数据时,又发送了一个ACK701,是为了确保服务器连接成功,因为如果三次握手时发送的ACK回应服务器没收到,就不能成功发送数据。
在这里插入图片描述

3、四次挥手(关闭连接)

四次挥手的原因是:半关闭
三次握手之后成功建立连接,服务器可以向客户端发送数,客户端也可以向服务器发送数据。这里客户户端关闭连接之后,服务器就只能发送数据,不能读取读取数据了。
为什么客户端半关闭之后,服务器可以向客户端发送数据?因为套接字里面有两个缓冲区,一个读缓冲区和一个写缓冲区,半关闭就相当于把写缓冲区关掉了,客户端无法向服务器发送数据,但是可以读服务器发送过来的数据。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯EDA设计与开发】立创开源社区分享的关于蓝桥被EDA真题与仿真题的项目分析

立创开源社区内有几个项目分享了往年 EDA 设计题目与仿真题&#xff0c;对此展开了学习。 【本人非科班出身&#xff0c;以下对项目的学习仅在我的眼界范围内发表意见&#xff0c;如有错误&#xff0c;请指正。】 项目一 来源&#xff1a;第十四届蓝桥杯EDA赛模拟题一 - 嘉立…

开源版禅道用于考核的解决方案

禅道的基本流程为&#xff1a;创建产品、创建计划、创建需求、创建项目、创建迭代、【关联需求】创建任务、维护任务、【根据任务】创建bug、解决bug 根据是否受禅道系统的基本流程管理&#xff0c;把角色分为两种&#xff0c;流程角色和其他角色。流程角色要管理对应的禅道流程…

网络爬虫采集工具

在当今数字化的时代&#xff0c;获取海量数据对于企业、学术界和个人都至关重要。网络爬虫成为一种强大的工具&#xff0c;能够从互联网上抓取并提取所需的信息。本文将专心分享关于网络爬虫采集数据的全面指南&#xff0c;深入探讨其原理、应用场景以及使用过程中可能遇到的挑…

C++无锁队列的原理与实现

目录 1.无锁队列原理 1.1.队列操作模型 1.2.无锁队列简介 1.3.CAS操作 2.无锁队列方案 2.1.boost方案 2.2.ConcurrentQueue 2.3.Disruptor 3.无锁队列实现 3.1.环形缓冲区 3.2.单生产者单消费者 3.3.多生产者单消费者 3.4.RingBuffer实现 3.5.LockFreeQueue实现 …

实现仿ChatGPT光标跟随效果

先看效果 实现效果 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>光标闪烁效果</title>…

【Java万花筒】Java脚本之舞:发现动态脚本的神奇力量

脚本大联合&#xff1a;Java生态中的动态脚本执行库详解 前言 在现代软件开发中&#xff0c;动态脚本的使用越来越受到重视。本文将深入探讨Java生态中几个重要的动态脚本执行库&#xff0c;包括Apache Groovy、ScriptEngine API、Nashorn、Kotlin Scripting和JRuby。通过对每…

网络安全需要对网络风险有独特的理解

迷失在翻译中&#xff1a;网络风险解释的脱节现实 在古印度的一个经典故事中&#xff0c;几个蒙住眼睛的人接近一头大象&#xff0c;每个人检查不同的部位。有人触摸树干&#xff0c;认为它像一条蛇。另一个摸到了一条腿&#xff0c;认为它是一棵树。还有一个拿着象牙的人&…

云平台性能测试之存储性能测试

一、认识存储磁盘IO 磁盘IO测试是指在性能测试过程中&#xff0c;对系统的磁盘读写操作进行测试和评估的过程。磁盘是计算机系统中重要的存储介质&#xff0c;对于许多应用程序来说&#xff0c;磁盘IO的性能影响着系统的整体性能。 在性能测试中&#xff0c;磁盘IO测试通常有…

高级编程,JavaScript笔记-字符串的常用方法

一、操作方法 我们也可将字符串常用的操作方法归纳为增、删、改、查&#xff0c;需要知道字符串的特点是一旦创建了&#xff0c;就不可变 增 这里增的意思并不是说直接增添内容&#xff0c;而是创建字符串的一个副本&#xff0c;再进行操作 除了常用以及${}进行字符串拼接之…

Java中打印图案最常用的25个图案程序

Java是公认的最流行的编程语言&#xff0c;因为它的简单性和多功能性。还可以使用它开发各种应用程序&#xff0c;包括Web、移动和桌面应用程序。此外&#xff0c;Java为开发人员提供了强大的工具来轻松高效地创建复杂的程序。Java最有前途的特性之一是它能够创建可以以特定格式…

《向量数据库指南》——为什么说向量数据库是更适合AI体质的“硬盘”

其“AI原生”的体质,具体表现在几个方面: 1.更高的效率。 AI算法,要从图像、音频和文本等海量的非结构化数据中学习,提取出以向量为表示形式的“特征”,以便模型能够理解和处理。因此,向量数据库比传统基于索引的数据库有明显优势。 2.更低的成本。 大模型要从一种新…

美易平台:美国阿特拉斯航空公司波音747 8型货机因发动机故障安全降落

正文&#xff1a; 据路透社报道&#xff0c;美国阿特拉斯航空公司的一架波音747 8型货机在从迈阿密国际机场起飞后不久&#xff0c;发动机出现故障&#xff0c;但幸运的是飞机成功安全降落。这一事件引起了人们对航空安全的关注。 根据航空信息网站Flightaware的数据显示&…

【stm32】hal库学习笔记-GPIO按键控制LED和蜂鸣器(超详细!)

【stm32】hal库学习笔记-GPIO按键控制LED和蜂鸣器 注&#xff1a;本学习笔记基于stm32f4系列 使用的开发板为正点原子stmf407ZGT6探索者开发板 GPIO引脚使用时&#xff0c;可输入或输出数字信号 例如: 检测按键输入信号&#xff08;Read_Pin&#xff09;输出信号&#xff08;W…

敏捷开发之开发流程

敏捷开发流程 一、迭代周期 我们团队的迭代周期一般是2周&#xff0c;如果研发评估时间过长的话也会将周期延长至一个月&#xff0c;但是大多数我们是2周的迭代周期。 这里说的2周是研发开始coding、提测、测试、上线&#xff0c;也就是说2周以后要上线相应的能力。并不包括…

flink operator 拉取阿里云私有镜像(其他私有类似)

创建 k8s secret kubectl --namespace flink create secret docker-registry aliyun-docker-registry --docker-serverregistry.cn-shenzhen.aliyuncs.com --docker-usernameops_acr1060896234 --docker-passwordpasswd --docker-emailDOCKER_EMAIL注意命名空间指定你使用的 我…

从0开始python学习-50.pytest之多接口用例封装

1. yaml用例设计--一个yaml中多个用例&#xff0c;且互相存在关联关系 - # 第一个用例request:method: posturl: http://192.168.0.1:8010/apijson:accounts: adminpwd: 123type: usernameheaders:Content-Type: application/json- # 第二个用例request:method: posturl: http:…

Linux:多线程

目录 1.线程的概念 1.1线程的理解 1.2进程的理解 1.3线程如何看待进程内部的资源? 1.4进程 VS 线程 2.线程的控制 2.1线程的创建 2.2线程的等待 2.3线程的终止 2.4线程ID 2.5线程的分离 3.线程的互斥与同步 3.1相关概念 3.2互斥锁 3.2.1概念理解 3.2.2操作理解…

分类预测 | Matlab实现WOA(海象)-XGboost分类【24年新算法】基于海象优化算法(WOA)优化XGBoost的数据分类预测

分类预测 | Matlab实现WOA(海象)-XGboost分类【24年新算法】基于海象优化算法(WOA)优化XGBoost的数据分类预测 目录 分类预测 | Matlab实现WOA(海象)-XGboost分类【24年新算法】基于海象优化算法(WOA)优化XGBoost的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本…

js控制浏览器前进、后退、页面跳转

在JavaScript中&#xff0c;你可以使用 window 对象的 history 对象来控制浏览器的历史记录。以下是一些常用的方法&#xff1a; 前进和后退&#xff1a; window.history.forward(): 前进到历史记录中的下一个页面。window.history.back(): 返回历史记录中的上一个页面。window…

模型的召回率(Recall)

召回率&#xff08;Recall&#xff09;&#xff0c;也称为灵敏度&#xff08;Sensitivity&#xff09;或真正例率&#xff08;True Positive Rate&#xff09;&#xff0c;是用于评估二分类模型性能的指标之一。召回率衡量了模型正确识别正例的能力&#xff0c;即在所有实际正例…