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

news2024/9/21 0:36:42

文章目录

    • 一、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 8087
 
void 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 8087

void 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.coloradmin.cn/o/1398758.html

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

相关文章

Android Termux技能大揭秘:安装MySQL并实现公网远程连接

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 安装MariaDB二. 安装cpolar内网穿透工具三. 创建安全隧道映射mysql四. 公网…

Linux下安装docker

1、查看系统版本 Docker支持64位版本的CentOS 7和CentOS 8及更高版本&#xff0c;它要求Linux内核版本不低于3.10。查看Linux版本的命令这里推荐两种&#xff1a;lsb_release -a或cat /etc/redhat-release。 显然&#xff0c;当前Linux系统为CentOS7。再查一下内核版本是否不低…

MCM备赛笔记——蒙特卡罗方法

Key Concept 蒙特卡罗方法&#xff08;Monte Carlo Method&#xff09;&#xff0c;也称为统计模拟方法&#xff0c;是一种基于概率和统计的数值计算方法。该方法使用随机数&#xff08;或更常见的伪随机数&#xff09;来解决可能非常复杂的数学或物理问题。蒙特卡罗方法广泛应…

关于xftp突然无法连接服务器或虚拟机,可以ping通自己的虚拟机ip地址

关于xftp突然无法连接服务器或虚拟机,ping自己的虚拟机ip地址可以ping通 主机能ping通虚拟机&#xff08;ubuntu&#xff09; C:\Users\42216\Desktop>ping 192.168.61.128正在 Ping 192.168.61.128 具有 32 字节的数据: 来自 192.168.61.128 的回复: 字节32 时间<1ms …

链表的相交

链表的相交 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/intersection-of-tw…

selenium自动化测试框架简介

工欲善其事必先利其器&#xff0c;对于自动化测试也是同样的道理。进入自动化测试之前&#xff0c;怎么能不了解我们都有哪些框架、工具&#xff0c;又有哪些是主流的呢&#xff1f;1. 行业自动化测试框集 对于大多数同学来说&#xff0c;并不需要全面了解自动化测试工具都有哪…

大数据导论(3)---大数据技术

文章目录 1. 大数据技术概述2. 数据采集与预处理2.1 数据采集2.2 预处理 3. 数据存储和管理3.1 分布式基础架构Hadoop3.2 分布式文件系统HDFS3.3 分布式数据库HBase3.4 非关系型数据库NoSQL 4. 数据可视化与保护 1. 大数据技术概述 大数据技术主要包括数据采集与预处理、数据存…

Linux指令(四)

1.more指令 我们知道cat指令是用来读取文本文件的&#xff0c;但是如果是大文件&#xff0c;其实是不适合cat读取的&#xff0c;原因是&#xff1a;cat读取会直接到文本的结尾&#xff0c;所以我们引入&#xff1a;more指令 该指令不会将文件直接读到结尾&#xff0c;而是将最…

GZ036 区块链技术应用赛项赛题第3套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷&#xff08;3卷&#xff09; 任 务 书 参赛队编号&#xff1a; 背景描述 新能源作为新兴领域&#xff0c;产业呈现碎片化与复杂化的特性&#xff0c;逐渐出现管理困难、供应链金融、可信监管与数…

在IDEA上运行成功,打包成jar包后,运行报错,程序自动退出

原因 java环境不正确&#xff0c;很有可能安装了多个环境&#xff0c;导致程序加载了错误程序。 解决办法 尝试修改环境变量&#xff0c;如果不行&#xff0c;建议删除掉多余的java环境。 注意&#xff1a;删除掉多余的Java环境需要用程序删除&#xff0c;直接删除文件&#xf…

史上最全软件测试面试题(含答案),进大厂涨薪必备

本试题分三部分&#xff0c;第一部分&#xff0c;基础面试题及答案&#xff0c;第二部分&#xff0c;高级进阶&#xff1b;第三部分&#xff0c;测试开发相关面试题&#xff0c;本篇为第一部分。 加粗样式建议&#xff0c;收藏后阅读&#xff0c;篇幅很长。 1、你的测试职业发…

用LED数码显示器循环显示数字0~9

#include<reg51.h> // 包含51单片机寄存器定义的头文件 /************************************************** 函数功能&#xff1a;延时函数&#xff0c;延时一段时间 ***************************************************/ void delay(void) { unsigned …

MCM备赛笔记——熵权法

Key Concept 熵权法是一种基于信息熵概念的权重确定方法&#xff0c;用于多指标决策分析中。信息熵是度量信息量的不确定性或混乱程度的指标&#xff0c;在熵权法中&#xff0c;它用来反映某个指标在评价过程中的分散程度&#xff0c;进而确定该指标的权重。指标的分散程度越高…

【SpringBoot】—— 如何创建SpringBoot工程

SpringBoot简化了Spring应用的初始搭建和开发过程。 工程创建 新建模块 出现java: 错误: 无效的源发行版&#xff1a;18这样的错误&#xff0c; 修改pom.xml文件 出现以下信息&#xff0c;即运行成功 修改默认端口 创建application.yml文件 内容&#xff1a; server:port:…

【Kafka】Linux本地和Docker安装Kafka

目录 Linux本地安装kafkajava环境配置Zookeeper的安装配置Kafka的安装与配置生产与消费 Docker安装kafkaZookeeper安装Kafka安装 Linux本地安装kafka java环境配置 1、上传jdk-8u261-linux-x64.rpm到服务器并安装&#xff1a; rpm -ivh jdk-8u261-linux-x64.rpm2、配置环境变…

电力能源实景三维可视化合集,智慧电网数字孪生

电力能源是现代社会发展和运行的基石&#xff0c;渗透于工业、商业、农业、家庭生活等方方面面&#xff0c;它为经济、生活质量、环境保护和社会发展提供了巨大的机会和潜力。图扑软件应用自研 HT for Web 强大的渲染引擎&#xff0c;助力现代化的电力能源数字孪生场景&#xf…

Oracle 12CR2 RAC部署翻车,bug避坑经历

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

C++初阶--自我实现vector

实现模板 #include<assert.h> #include<string.h> #include<iostream> #include<list> using namespace std; namespace fnc {template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;//构造函数vector(){…

CSS 浮动 定位

文章目录 网页布局的本质浮动如何设置浮动测试浮动 定位相对定位绝对定位测试定位 网页布局的本质 用 CSS 来摆放盒子&#xff0c;把盒子摆放到相应位置。 CSS 提供了三种传统布局方式&#xff08;简单说就是盒子如何进行排列&#xff09;。 普通流&#xff08;标准流&#…

Postman接口测试基本操作(超详细)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 Postman-获取验证码 需求&#xff1a;使用Postman访问验证码接口&#xff0c;并查看响应结果…