IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【TCP/IP网络编程】(01):什么是网络编程 -> 正文阅读

[网络协议]【TCP/IP网络编程】(01):什么是网络编程

什么是网络编程

网络编程简单来说就是编程使得计算机之间交互数据。

硬件部分已经接入了互联网中,我们需要考虑的是软件部分。

软件部分有OS提供的套接字。

套接字

套接字用于网络数据传输,这个名字看上去很奇特。socket也是“插座”的意思,意味着可以进行连接,就像用电设备连入电网一样。

套接字的构建

首先以TCP套接字为例,我们把它比为电话机

1.调用socket

首先需要安装电话机,对socket进行创建

#include <sys/socket.h>
int socket(int domain,int type,int protocol);

2.调用bind函数

有了电话机,我们需要分配电话号码,也就是给socket分配IP地址和端口号。

#include <sys/socket.h>
int bind(int sockfd,struct sockaddr *myaddr,socklen_t addrlen);

3.调用listen函数

下一步需要连接电话线,转为接听状态

#include <sys/socket.h>
int listen(int sockfd,int backlog);

4.调用accept函数

电话来了当然是要接听的,这样才能接受对方的连接请求

#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)

以上就是套接字编程的基本流程了。

服务端和客户端

如何区分服务端还是客户端?

简单来说,服务端就是在后方默默服务的部分,主要用于接收请求,而客户端是要和用户进行交互的部分,主要是发送请求。

客户端在请求连接的时候,也会创建客户端套接字。

#include <sys/socket.h>
int connect(int sockfd,struct sockaddr *servaddr,socklen_t addrlen);

客户端只需要:

1.调用socket函数

2.调用connect函数发送

套接字协议

前面说完了创建sokcet,接下来细说其参数

int socket(int domain,int type,int protocol);

1.domain:套接字使用的协议族

2.type:套接字数据传输类型

3.protocol:计算机之间通信的协议

协议族

对于socket的协议族来说,PF_INET代表IPV4协议族,PF_INET6代表IPV6协议族。

第三个参数才是socket实际使用的协议。

套接字类型

1.面向连接的套接字

SOCK_STREAM,创建面向连接的套接字。(TCP)

数据会按顺序传递,并且不会消失。

并且有buffer,可以保存数据,在读取时可以一次性全部读出,也可以分几次读取。

如果明白TCP的原理,那么可以知道在缓冲区满时会停止传输,并且有重传机制。

2.面向消息的套接字

SOCK_DGRAM,创建面向消息的套接字(UDP)

速度更重要, 不按顺序,并且有可能会丢失数据。

而且数据传输有大小限制,接收数据次数与传输次数也相同。

基于UDP,所以遵循UDP的原理

协议选择

第三个参数负责选择协议。当协议族和类型确定之后,大部分情况都不需要第三个参数可为0。

除了一种情况,同一个协议族(比如IPV4)有多个数据传输方式相同的协议。

对于PF_INET+SOCK_STREAM的组合来说,只有IPPROTO_TCP一个协议。

对于PF_INET+SOCK_DGRAM的组合来说,只有IPPROTO_UDP一个协议。

地址族与数据序列

创建socket的下一步是调用bind函数,来分配IP地址和端口号。

IP地址分类IPV4和IPV6,IPV4又根据网络段和主机段分为ABCDE五类。(详解见计算机网络部分)

根据IP地址可以找到目标主机,而想要传输到对应的应用程序,就需要端口号了。

其中0-1023是用于分配给特定应用的知名端口。0-65535都是端口号的范围(2的16次方)

TCP套接字和UDP套接字的端口号可以重复,因为不会共用。

地址信息

在得到地址信息时,需要对三个问题进行回答。

1.采用什么地址族?IPV4

2.IP地址是多少?192.168.0.11

3.端口号是多少?2048

由此可以得到sockaddr_in结构体

struct sockaddr_in
{
	sa_family_t sin_family;//地址族
	uint16_t sin_port;//16位端口号
	struct in_addr sin_addr;//32位IP地址
	char sin_zero[8];//不使用
}

其中in_addr定义如下:

struct in_addr
{
	in_addr_t s_addr;//32位IP地址
}

数据类型

sa_family_t代表地址族。

unint16_t代表unsigned 16bit int。

in_addr_t 表示IP地址,声明为uint32_t;

结构体成员

sin_family用来保存地址族。比如AF_INET代表IPV4地址族,AF_INET6代表IPV6地址族。

sin_port保存16位端口号。

sin_addr保存32位IP地址,可以看该结构体的定义。(结构体的形式可能是为了可扩展性)

回到bind函数

bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)

这里bind函数的第二个参数希望得到sockaddr的地址族,端口号,IP地址等信息。

而bind函数要求sockaddr结构体这样是这样的:

struct sockaddr
{
	sa_family_ sin_family;//地址族
	char sa_data[14];//地址信息
}

这里sa_data保存地址信息中需要的IP和端口号。但比较麻烦,于是设计出子结构体,也就是我们上面看到的sockaddr_in。最后将其转换位sockaddr型的结构体变量。

这里的serv_addr就是sockaddr_in类型的。

struct sockaddr_in serv_addr;

所以我们上面看到的不使用的sin_zero[8]字段其实是为了进行填充,让其与sockaddr保持一致。

网络字节序

前面的16位端口号和32位IP地址,都是以网络字节序存储的。

我们都知道CPU向内存保存数据时有两种方式:大端序和小端序。

比如0x12345678,最高位是0x12,最低位是0x78.

在大端序中,最高位存放在低位地址。而小端序则相反,最低位存放在低位地址。

正是因为数据保存的顺序不同,所以在网络传输时需要约定好统一的方式,叫做网络字节序。

网络字节序统一为大端序。

而我们常用的intelCPU则是使用小端序,所以在接收数据时需要转换。(当然实际使用中无需手动转换)

字节序转换

字节序转换主要用到四个函数:

unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);

根据名字也非常好理解。

h是host主机,n是network网络。

htons就是把short类型的数据从主机字节序转化为网络字节序。

ntohs就是把short类型的数据从网络字节序转化为主机字节序。

short用于端口号转换,long用于IP地址转换。

网络地址转换

inet_addr

前面说到,sockaddr_in保存地址信息是32位的,而我们日常使用的IP地址一般都是字符串信息。比如192.168.1.1

所以需要进行IP地址的转换

#include <arpa/inet.h>
in_addr_t inet_addr(const char* string);

这个函数可以将字符串形式的IP地址转换为32位整形数据,同时转换网络字节序。

char *addr1="1.2.3.256";
unsigned long conv_addr=inet_addr(addr1);

输出:
0x04030201

inet_aton

inet_addr函数的升级版就是这个inet_aton,该函数直接利用了in_addr结构体。

#include <arpa/inet.h>
int inet_aton(const char* string,struct in_addr *addr)

这样就不需要在转换IP地址后代入到sockaddr_in的in_addr结构体中。

char *addr="1.2.3.256";
struct sockaddr_in addr_inet;

if(!inet_aton(addr,&addr_inet.sin_addr))
	error_handling("conversion error");
else
	printf("Network ordered integer addr:%#x \n",addr_inet.sin_addr.s_addr)
    
    
输出:
Network ordered integer addr:0x04030201

inet_ntoa

也有一个函数用来将IP地址转换为字符串形式。

#include <arpa/inet.h>
char* inet_ntoa(struct in_addr adr);

需要注意的是返回值为字符串。所以调用后需要保存字符串,否则二次调用就会覆盖掉。

struct sockaddr_in addr1;
chr *str_ptr;
char str_arr[20];

addr1.sin_addr.s_addr=htonl(0x1020304);

str_ptr=inet_toa(addr1.sin_addr);
strcpy(str_arr,str_ptr);;
printf(str_ptr);

输出:
1.2.3.4

服务端初始化

根据上面了解的知识,我们可以写出服务端初始化的过程:

int serv_sock;
struct sockaddr_in serv_addr;
char* serv_port="9190";

//创建套接字
serv_sock=socket(PF_INET,SOCK_STREAM,0);

//初始化信息
memset(&serv_adr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(atoi(serv_port));

//分配地址信息
bind(serv_sock,(struct sockaddr*)&serv_addr),sizeof(serv_addr));

还有几个需要注意的点:

  1. memset函数将每个字节初始化为同一个值,这里就是0
  2. INADDR_ANY可以免去每次输入IP地址的步骤,自动获取计算机IP地址。
  3. atoi是把对应的字符串转换为数字

这样,我们就了解了网络编程的基本内容,在搭建基础的服务端客户端时这些知识会成为骨架。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:56:30  更:2022-03-16 22:57:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:30:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码