Linux网络编程(七)-TCP协议客户端及代码实现

1.TCP的客户端代码流程简述

这一章将为大家讲解Socket通信中客户端的实现过程,还是先上图,请大家了解客户端的步骤

可以看到,相比服务端,客户端的步骤简单的很多。事实上这种情况比较多,比如一个服务端会有多个客户端连接。

通过图片我们可以看到TCP客务端调用的函数依次是socket( )、connect( )、recv( )、send( )、closessocket( )

由于在服务端这章的讲解中我们提到了socket()、recv()、send()、closesocket()、WSAStartup()、WSACleanup()的函数,在客户端中同样需要这些函数,使用方式是一样的,因此这里不再赘述。

大家学习前面的函数后可直接在客户端中实现。

 2.Socket编程之connect函数

这一节我们讲connect连接,这一步位于客户端的第二步,调用connect阻塞客户程序,传输层实体开始建立连接,当连接建立完成时,取消阻塞;

函数功能:

向服务端发起连接请求

头文件:

#include <winsock2.h>

函数原型:

int connect(int sockcd, const struct sockaddr *addr, int addrlen);

返回值类型:

整型

返回值:

成功返回0,失败返回-1。当客户端调用 connect()函数之后,发生以下情况之一才会返回(完成函数调用)

  1. 服务器端接收连接请求
  2. 发生断网的异常情况而终端连接请求

参数说明:

sockcd为客户端建立socket函数的返回值。

addr是一个sockaddr结构的指针,用于指定所要连接的服务器的地址(服务端的IP地址和端口号,要和服务端的实际IP地址以及绑定的端口一致才可以)。

addrlen为addr变量的大小,可由 sizeof()计算得出。

调用connect函数整体代码的实现:

accept()函数,其实是服务器端把连接请求信息记录到等待队列。因此connect()函数返回后并不进行数据交换。而是要等服务器端 accept 之后才能进行数据交换。、

这一步调用完成之后,就和服务端建立了通信,就可以使用send或recv相互发送和接收消息了

connect(sockcd,(sockaddr*)&seraddr,sizeof(seraddr));//需要注意的是,所谓的“接收连接”并不意味着服务器调用

3.Socket客户端完整参考代码

 本代码用于和第二章服务端代码一致,监听12345端口,可以不断的发送消息,直至输入"quit"退出程序,完整参考代码如下:

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")int main()
{int err;char SendBuf[100];WORD versionRequired;WSADATA wsaData;versionRequired=MAKEWORD(2,2);err=WSAStartup(versionRequired,&wsaData);//协议库的版本信息//通过WSACleanup的返回值来确定socket协议是否启动if (!err){printf("客户端套接字已经打开!\\n");}else{printf("客户端套接字打开失败!\\n");return -1;//结束}//注意socket这个函数,他三个参数定义了socket的所处的系统,socket的类型,以及一些其他信息SOCKET clientSocket=socket(AF_INET,SOCK_STREAM,0);//socket编程中,它定义了一个结构体SOCKADDR_IN来存计算机的一些信息,像socket的系统,//端口号,ip地址等信息,这里存储的是服务器端的计算机的信息SOCKADDR_IN clientsock_in;clientsock_in.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");clientsock_in.sin_family=AF_INET;clientsock_in.sin_port=htons(12345);//前期定义了套接字,定义了服务器端的计算机的一些信息存储在clientsock_in中,//准备工作完成后,然后开始将这个套接字链接到远程的计算机//也就是第一次握手int r=connect(clientSocket,(SOCKADDR*)&clientsock_in,sizeof(SOCKADDR));//开始连接// printf("%d\\n",r);while(1){gets(SendBuf);if(strcmp(SendBuf,"quit")==0)break;send(clientSocket,SendBuf,strlen(SendBuf)+1,0);}closesocket(clientSocket);//关闭服务WSACleanup();return 0;
}

单独运行客户端,如下图效果:

 

 若是连同前面的服务端一起测试,先运行服务端,再运行客户端,即可完成通信效果,效果图下:

 从图中可以看到,客户端向服务端发送三条消息,服务端都已接收,并打印长度和消息信息,第四条信息退出,之后双方退出结束程序。

4.什么是字节序?大小端还有网络序和主机序?

1.字节序

字节序,又称端序或尾序,指的是多字节数据在内存中的存放顺序。学过C语言后,我们知道一个int型变量a是占用4个字节,假设它的起始地址也就是&a是0x10处,那么变量a的四个字节将会被存储在0x10、0x11、0x12和0x13这四个字节位置上。

但是当我们写好通信程序发送数据时候的时候,这个a变量通过TCP连接传输后收到的与发送的不一致,即有可能发过去的序列变成了0x12、0x13的值在前,0x10、0x11上的值在后,这样组成的四个字节的int类型值肯定就不一样了。

所以要引入大端和小端的概念。

2.大端和小端

计算机有两种储存数据的方式:大端字节序(Big Endian)和小端字节序(Little Endian)。

  • 大端模式:是指数据的高字节保存在内存的低地址中,低字节保存在内存的高地址端
  • 小端模式:是指数据的高字节保存在内存的高地址中,低字节保存在内存的低地址端。

以一个两字节short型变量0x0102的存储举例:

大端字节序:高位字节在前,低位字节在后,01|02,从左往右看着更习惯。

小端字节序:低位字节在前,高位字节在后,02|01,也存在这种存储顺序。

我们以0x12345678这个数字为例,它的大端模式和小端模式分别如下:

3.原因

计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节。它只知道按顺序读取字节,先读第一个字节,再读第二个字节…

如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节;小端字节序正好相反。

如果这样,那统一用符合我们人类读写习惯的大端序就好了呀,为何还要弄出个小端序了?

这是疑问计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的,所以计算机的内部处理都是小端字节序。

但是人类还是习惯读写大端字节序,所以除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存。

4.网络序和主机序

明白了大小端之后,网络序和主机序也就好理解了,

  • 网络字节序:TCP/IP各层协议将字节序定义为Big Endian,即大端模式,TCP/IP协议中使用的字节序是大端序。
  • 主机字节序:整数在内存中存储的顺序,目前以Little Endian,即小端模式,比较普遍(不同的CPU有不同的字节序)。

C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而现在比较普遍的x86处理器是小端模式(Little Endian)。Java编写的程序则唯一采用Big Endian方式来存储数据。

所以,如果你的C/C++程序通过Socket将变量a = 0x12345678的首地址传递给了Java程序,由于Java采取Big Endian方式存取数据,很显然,本地数据没问题,传过去就变成0x78563412,这就出问题了。毕竟不是所有的客户端和服务端都是同一种语言、同一种CPU。因此转换的问题就来了

5.如何转换

为避免开头说到的网络通信中存在的问题,我们可以在传输数据之前和接收数据之后对数据进行相应处理,也就是主机序和网络序的转换。

C/C++提供了相应的函数接口,htons、htonl用于主机序转换到网络序,ntohl、ntohs用于网络序转换到主机序。

5.htos和htol函数

主机序转换到网络序

在网络传输过程中,一定会涉及到主机序和网络序的问题,即本机的存储和网络的传输是完全两套存储方式,我们保证不了目标主机的字节序是否和网络序一致,因此一定要考虑这个问题,这里介绍常用的两个函数htos和htol函数,使主机序转换到网络序

1.htos函数:

函数功能:

将主机无符号短整形数转换成网络,比如古人读12345的顺序是从右往左54321,而现代人读12345的顺序是从左往右读12345,htos函数就是完成类似的转换功能,举例说明如果把htons(16)输出你会看到得到的结果是4096,为什么呢?因为16的十六进制是0X0010,而4096的十六进制是0X1000。不同的存储方式,会导致高低位存储时顺序的不同,这就是即00 10和10 00 的存储不同的原因。

头文件:

#include <winsock2.h>

函数原型:

uint16_t htons(uint16_t hostlong);

返回值类型:

整型

返回值:

返回一个网络字节顺序的值

参数说明:

其中hostlong是主机字节顺序表达的16位数,htons中的h表示host意思是主机地址,to表示to意思是去往,转换为的意思,n表示net意思是网络,s表示signed long意思是无符号的短整型。

调用htos函数代码举例;

htos(5200);

2.htol函数

函数功能:

将一个32位数从主机字节顺序转换成网络字节顺序。

头文件:

#include <winsock2.h>

函数原型:

uint16_t htons(uint32_t hostlong);

返回值类型:

整型

返回值:

返回一个网络字节顺序的值

参数说明:

其中hostlong是主机字节顺序表达的32位数,htons中的h表示host意思是主机地址,to表示to意思是去往,转换为的意思,n表示net意思是网络,l 是 unsigned long表示32位长整数

调用htol函数代码举例;

htol( 0x403214);

6. ntohl和ntohs函数:网络序转换到主机序

 有主机序转网络序,就有网络序转主机序,分别是ntohl和ntohs函数,接下来为大家讲解这两个函数。

1.ntohl函数

函数功能:

将一个无符号短整型数从网络字节顺序转换成主机字节顺序。这个函数与htons原理相同,不过是htos是主机序到网络序,而ntohs是网络序到主机序。

头文件:

#include <winsock2.h>

函数原型:

uint16_t ntohs(uint16_t netshort);

返回值类型:

整型

返回值:

返回一个主机字节顺序表达的数。

参数说明:

其中netshort一个以网络字节顺序表达的16位数,ntohs中的h表示host意思是主机地址,to表示to意思是去往,n表示net意思是网络,s表示signed long意思是无符号的短整型(32位的系统是2字节)。

调用ntohs函数代码举例;

ntohs(5200);

2.ntohl函数

函数功能:

将一个无符号长整型从网络字节顺序转换成主机字节顺序。这个函数与htonl原理相同,不过是htol是主机序到网络序,而ntohl是网络序到主机序。

头文件:

#include <winsock2.h>

函数原型:

uint16_t ntohs(uint16_t netlong);

返回值类型:

整型

返回值:

返回一个主机字节顺序表达的数。

参数说明:

其中netlong一个以网络字节顺序表达的32位数,ntohs中的h表示host意思是主机地址,to表示to意思是去往,n表示net意思是网络,s表示signed long意思是无符号的短整型(32位的系统是2字节)。

调用ntohl函数代码举例;

ntohl( 0x403214);

7. Sockaddr_in和Sockaddr的区别

 sockaddr和sockaddr_in都是结构体,并且它们的功能都是用来处理网络通信的地址。网络中的地址主要有3个方面的属性:

  1. 地址类型,例如是互联网协议第四版(ipv4)和互联网协议第六版(ipv6)。

  2. IP地址,主要有5类分别是

    A类:(1.0.0.0-126.0.0.0),地址的网络号取值于1~126之间。一般用于大型网络。

    B类:(128.0.0.0-191.255.0.0),地址的网络号取值于128~191之间。一般用于中等规模网络。

    C类:(192.0.0.0-223.255.255.0),地址的网络号取值于192~223之间。一般用于小型网络。

    D类:是多播地址,地址的网络号取值于224~239之间。一般用于多路广播用户  。

    E类:是保留地址,地址的网络号取值于240~255之间。

  3. 端口,它就像门牌号一样,客户端可以通过ip地址找到对应的服务器端,但是服务器端有很多端口,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号,范围是0---65535。

用于存储参与(IP)Windows套接字通信的计算机上的一个internet协议(IP)地址。为了统一地址结构的表示方法 ,统一接口函数,使得不同的地址结构可以被bind()、connect()、recv()、send()等函数调用。但一般的编程中并不直接对此数据结构进行操作,而使用另一个与之等价的数据结构sockaddr_in。这是由于Microsoft TCP/IP套接字开发人员的工具箱仅支持internet地址字段,而实际填充字段的每一部分则遵循sockaddr_in数据结构,两者大小都是16字节,所以二者之间可以进行切换。

sockaddr_in中的in就表示internet也就是网络地址的意思,它弥补了sockaddr的缺陷,把port(端口号),和addr(目标地址)分开存储在两个变量中。

总结

二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。

sockaddr常用于bind、connect、recv、send等函数的参数,指明地址信息,是一种通用的套接字地址。

sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用强制类型转化就可以了。一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。

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

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

相关文章

JMeter模拟并发请求

PostMan不是严格意义上的并发请求工具&#xff0c;实际是串行的&#xff0c;如果需要测试后台接口并发时程序的准确性&#xff0c;建议采用JMeter工具。 案例&#xff1a;JMeter设置20个并发卖票请求&#xff0c;查看后台是否存在超卖的情况 方式一&#xff1a;一共10张票&…

TrickMo 安卓银行木马新变种利用虚假锁屏窃取密码

近期&#xff0c;研究人员在野外发现了 TrickMo Android 银行木马的 40 个新变种&#xff0c;它们与 16 个下载器和 22 个不同的命令和控制&#xff08;C2&#xff09;基础设施相关联&#xff0c;具有旨在窃取 Android 密码的新功能。 Zimperium 和 Cleafy 均报道了此消息。 …

编写一个通用的i2c控制器驱动框架

往期内容 I2C子系统专栏&#xff1a; I2C&#xff08;IIC&#xff09;协议讲解-CSDN博客SMBus 协议详解-CSDN博客I2C相关结构体讲解:i2c_adapter、i2c_algorithm、i2c_msg-CSDN博客内核提供的通用I2C设备驱动I2c-dev.c分析&#xff1a;注册篇内核提供的通用I2C设备驱动I2C-dev.…

时空数据时序预测模型: HA、VAR、GBRT、GCN、DCRNN、FCCF、ST-MGCN

HA (Historical Average) HA (Historical Average&#xff0c;历史平均模型) 是一种基础的时间序列预测方法&#xff0c;通常用于预测具有周期性或季节性规律的数据。它通过计算历史上同一时间段的平均值来预测未来值&#xff0c;假设数据会遵循某种周期性的变化模式。以下是对…

智能家居的“眼睛”:计算机视觉如何让家更智能

引言 在不远的未来&#xff0c;当我们走进家门&#xff0c;灯光自动亮起&#xff0c;空调已经调至最舒适的温度&#xff0c;甚至音乐也播放着我们最喜欢的歌曲。 这一切&#xff0c;都得益于智能家居系统的发展。而在这个系统中&#xff0c;计算机视觉技术扮演着至关重要的角色…

SpringBoot车辆管理系统:构建与优化

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

群晖通过 Docker 安装 MySQL

1. 打开 Docker 应用&#xff0c;并在注册表搜索 MySQL 2. 下载 MySQL 镜像&#xff0c;并选择版本 3. 在 Docker 文件夹中创建 MySQL&#xff0c;并创建子文件夹 4. 设置权限 5. 选择 MySQL 映像运行&#xff0c;创建容器 6. 配置 MySQL 容器 6.1 使用高权限执行容器 6.2 启…

scrapy 爬虫学习之【中医药材】爬虫

本项目纯学习使用。 1 scrapy 代码 爬取逻辑非常简单&#xff0c;根据url来处理翻页&#xff0c;然后获取到详情页面的链接&#xff0c;再去爬取详情页面的内容即可&#xff0c;最终数据落地到excel中。 经测试&#xff0c;总计获取 11299条中医药材数据。 import pandas as…

idea 2023 配置 web service

前言 能在网上查到的资料,都是比较老的,搞了一上午才配置好了环境 因此记录一下,服务你我他 我的环境: java 1.8,Idea2023.1 配置web service 服务端 直接新建一个java新项目 下载插件 添加框架支持 启动项目 配置web service 客户端 新建项目,下载三个插件的步骤和上面服务…

JMeter之mqtt-jmeter 插件介绍

前言 mqtt-jmeter插件是JMeter中的一个第三方插件&#xff0c;用于支持MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议的性能测试。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;广泛应用于物联网和传感器网络中。 一、安装插件 mqtt-jmeter项目…

【Hive】6-Hive函数、运算符使用

Hive函数、运算符使用 Hive内置运算符 概述 整体上&#xff0c;Hive支持的运算符可以分为三大类&#xff1a;关系运算、算术运算、逻辑运算。 官方参考文档&#xff1a;https://cwiki.apache.org/confluence/display/Hive/LanguageManualUDF 也可以使用下述方式查看运算符的…

2024年AI 制作PPT新宠儿,3款神器集锦,让你的演示与众不同

咱们今儿聊聊最近超火的AI做PPT的工具。这年头&#xff0c;谁不想省事儿&#xff0c;少熬夜加班&#xff0c;多享受享受生活啊&#xff1f;所以&#xff0c;AI开始帮咱们搞定做PPT这种费时的活儿&#xff0c;我自然得好好研究研究。今天&#xff0c;我就给大家详细说说三款很火…

Linux下的进程解析(level 2)

目录 引言 pid解析 /proc 系统调用 fork &#xff1a;创建子进程 执行流分析 父子进程谁先运行 引言 在当今的信息技术时代&#xff0c;操作系统作为计算机系统的核心组件&#xff0c;承担着资源管理、任务调度等重要职责。Linux作为一种开源、高性能的操作系统&#xf…

第11篇:网络安全协议

目录 引言 11.1 安全套接字层&#xff08;SSL&#xff09;和传输层安全&#xff08;TLS&#xff09;协议 11.1.1 SSL/TLS 的工作原理 11.1.2 SSL/TLS 的应用场景 11.2 虚拟专用网&#xff08;VPN&#xff09;和 IP 安全协议&#xff08;IPSec&#xff09; 11.2.1 VPN 的工…

《深度学习》OpenCV EigenFaces算法 人脸识别

目录 一、EigenFaces算法 1、什么是EigenFaces算法 2、原理 3、实现步骤 1&#xff09;数据预处理 2&#xff09;特征提取 3&#xff09;构建模型 4&#xff09;识别 4、优缺点 1&#xff09;优点 2&#xff09;缺点 二、案例实现 1、完整代码 运行结果&#xff…

9.存储过程安全性博客大纲(9/10)

存储过程安全性博客大纲 引言 在数据库系统中&#xff0c;存储过程是一种预先编写好的SQL代码集合&#xff0c;它被保存在数据库服务器上&#xff0c;可以通过指定的名称来调用执行。存储过程可以包含一系列的控制流语句&#xff0c;如IF条件语句、WHILE循环等&#xff0c;使…

「从零开始的 Vue 3 系列」:第十一章——跨域问题解决方案全解析

前言 本系列将从零开始&#xff0c;系统性地介绍 Vue 3 的常用 API&#xff0c;逐步深入每个核心概念与功能模块。通过详尽的讲解与实战演示&#xff0c;帮助大家掌握 Vue 3 的基础与进阶知识&#xff0c;最终具备独立搭建完整 Vue 3 项目的能力。 第十一章&#xff1a;跨域问…

Win32图片库CxImage在vs2022下的编译和使用

一、编译CxImage库 1、下载CxImage_702库的源码:在下面的链接中下载cximage702_full.7z https://sourceforge.net/projects/cximage/files/7.02/ 2、解压到某一目录&#xff0c;vs2022打开CxImageFull_vc10.sln解决方案文件&#xff0c;提示升级点确定 3、先编译下面的这几…

基于SSM+微信小程序的房屋租赁管理系统(房屋2)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM微信小程序的房屋租赁管理系统实现了有管理员、中介和用户。 1、管理员功能有&#xff0c;个人中心&#xff0c;用户管理&#xff0c;中介管理&#xff0c;房屋信息管理&#xff…

[Linux] 逐层深入理解文件系统 (2)—— 文件重定向

标题&#xff1a;[Linux] 逐层深入理解文件系统 &#xff08;2&#xff09;—— 文件重定向 个人主页水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 一、文件的读取和写入 二、文件重定向的本质 1.手动模拟重定向的过程——把标准输出重定向到redir.txt 2.重定向…