【Linux】【网络】UDP、TCP 网络接口及使用

2023-09-14 19:56:16


socket 及 相关补充

Socket 是一种通信机制,通过它可以在不同主机之间进行数据交换。

  • 在Socket 编程中,有两种常见的通信模式:客户端-服务器模式点对点模式

  • 它基于 TCP/IP 协议栈,并使用 IP地址端口号 来标识通信的目标。

  • Socket 编程可以通过 TCP(传输控制协议)UDP(用户数据报协议) 实现不同类型的连接。

  • socket 接口 创建的是文件,不同主机通过这个接口进行通信,即 网络通信依附的也是文件系统

0. netstat - - 查询当前服务器上网络服务器

netstat -naup:

-n:拒绝显示别名,能显示数字的全部转化成数字
-a:(all)显示所有选项
-u:(udp)仅显示 udp 相关选项
-p:显示建立相关链接的程序名

netstat -nltp:

-n:拒绝显示别名,能显示数字的全部转化成数字
-l:仅列出有在 Listen (监听) 的服务状态
-t:(tcp)仅显示tcp相关选项
-p:显示建立相关链接的程序名

1. 端口号(port)

端口号是传输层协议的内容

  • 数据类型为 uint16_t,即 16 位的 2 字节整数

  • 一个端口号只能标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理

  • IP地址 + 端口号,就能够标识网络上的某一台主机的某一个进程

注意:进程 pid 是唯一表示的,端口号也是唯一表示的,没有必然关系,就好比身份证和工号自己标记自己的

2. 网络字节序

讨论网络字节序还是主机字节序的意义,保证了主机能正确收发数据信息

发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,这需要接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存。

网络数据流的地址这样规定:先发出的数据是低地址,后发出的数据是高地址。

  • TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址高字节。
  • 不管这台主机是大端机还是小端机,都会按照这个 TCP/IP 规定的网络字节序来发送/接收数据。
  • 如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可。

网络字节序和主机字节序的转换:

#include <arpa/inet.h>
	
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohl(uint16_t hostshort);
  • h 表示 host,n 表示 network,l 表示 32 位长整数,s 表示 16 位短整数。

  • 接收和发送端口号,用这些接口转化

例如:htonl 表示将 32 位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。

如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

3. sockaddr 结构体

是用于储存网络地址信息的结构体,实现了多态。

IPv4 和 IPv6 的地址格式定义在 头文件 netinet/in.h

IPv4 地址用 sockaddr_in 结构体表示,包括:

  • 16 位地址类型
  • 16 位端口号和
  • 32 位 IP 地址
/* Structure describing an Internet socket address.  */
struct sockaddr_in
{
	__SOCKADDR_COMMON (sin_);	/*16位地址类型*/
	in_port_t sin_port;			/* Port number.端口号,无符号16位整数*/
	struct in_addr sin_addr;	/* Internet address.IP 地址,无符号32位整数*/
	
	/* Pad to size of `struct sockaddr'.  */
	unsigned char sin_zero[sizeof (struct sockaddr) -
		  __SOCKADDR_COMMON_SIZE -
		  sizeof (in_port_t) -
		  sizeof (struct in_addr)];
 };

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  */

#define	__SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family
  • IPv4 地址类型 定义为常数 AF_INET

  • IPv6 地址类型 定义为常数 AF_INET6

这样,只要取得某种 sockaddr 结构体的首地址不需要知道具体是哪种类型的 sockaddr 结构体,就可以根据地址类型字段确定结构体中的内容。

  • socket API 可以都用 struct sockaddr * 类型表示,在使用的时候需要强制转化成 sockaddr_in

这样的好处是程序的通用性,可以接收 IPv4、IPv6、以及 UNIX Domain Socket 各种类型的 sockaddr 结构体指针做为参数


一、socket 常见 API

UDP

0. IP 地址转化 函数

// 字符串风格的 IP 地址,转换成为 4 字节 int,同时将主机序列转化成为网络序列
in_addr_t inet_addr(const char *cp);

// 4 字节 int,转化为字符串风格 IP 地址
char *inet_ntoa(struct in_addr in);

// string 类型 IP 地址,转换成网络序列的 4 字节 IP 地址
// &struct sockaddr.sin_addr(点的优先级高)
int inet_aton(const char *cp, struct in_addr *inp);

1. socket 函数:创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

#include <sys/types.h>         
#include <sys/socket.h>

网络通信依附的也是文件系统!创建的是文件描述符。

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

参数 domian(地址类型,即选择通信方式):

  • AF_INET,IPv4 网络通信
  • AF_INET6,IPv6 网络通信
  • AF_UNIX,本地通信

参数 type:

  • SOCK_STREAM,流式套接(TCP)
  • SOCK_DGRAM,用户数据报(支持无连接、不可靠的数据通信,UDP)

参数 protocol:

  • 默认设为 0,就可以自动识别是 TCP 还是 UDP

返回值:

  • 创建成功返回文件描述符,创建失败返回 -1,并设置错误码

2. bind 函数:绑定端口号 (TCP/UDP, 服务器)

比如我们在实现某个函数时对 socket 进行了填充,可是创建的都是临时变量,于是就需要使用 bind 对填充数据进行于 socket 的绑定

#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int bind(int socket, const struct sockaddr *address, socklen_t address_len);

参数 socket:

  • 套接字的文件描述符

参数 address:

  • 用户自定义的用于填充数据的结构体,需要强转成 (struct sockaddr*) 使用

参数 address_len:

  • 实际传入 address 的大小,即 sizeof(address)

返回值:

  • 成功返回 0 ,失败返回 -1

3. recvfrom 函数:接收来自socket的信息

#include <sys/types.h>         
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
 	               struct sockaddr *src_addr, socklen_t *addrlen);  

参数 sockfd:

  • 服务端所绑定的套接字,后续接收和访问都从这里来

参数 buf:

  • 未来读到的数据要放在哪一个用户或者缓冲区里

参数 len:

  • 缓冲区的长度

参数 flags:

  • 0,默认以阻塞方式读取

参数 src_addr:

  • 接收缓冲区,获取到客户端的 IP 和 端口号,需要强转成 (struct sockaddr*) 使用

参数 addrlen:

  • 接收缓冲区的大小的地址

返回值:

  • 成功则返回接收的字节数,失败返回 -1 并设置错误码

4. sendto 函数:发送信息给socket

#include <sys/types.h>         
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                  const struct sockaddr *dest_addr, socklen_t addrlen);

参数 sockfd:

  • 服务端所绑定的套接字,后续接收和访问都从这里来

参数 buf:

  • 未来发送的数据是哪一个用户或者缓冲区里的

参数 len:

  • 缓冲区的长度

参数 flags:

  • 0,默认以阻塞方式调用

参数 dest_addr:

  • 发送缓冲区,需要发送到哪一个客户端,需要强转成 (struct sockaddr*) 使用

参数 addrlen:

  • 接收缓冲区的大小

返回值:

  • 成功则返回发送的字节数,失败返回 -1 并设置错误码

TCP

1. listen 函数:开始监听socket (TCP, 服务器)

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

参数 sockfd:

  • 监听的套接字的文件描述符

参数 backlog:

  • 一个整数

返回值:

  • 成功返回 0,失败返回 -1,并设置错误码

2. accept 函数:接收连接请求 (TCP, 服务器)

#include <sys/types.h>
#include <sys/socket.h>
int accept(int socket, struct sockaddr* address, socklen_t* address_len); 

参数 socket:

  • 监听套接字的文件描述符

参数 address:

  • 接收缓冲区,获取到客户端的 IP 和 端口号,需要强转成 (struct sockaddr*) 使用

参数 address_len:

  • 接收缓冲区的大小的地址

返回值:

  • 如果接收成功,返回一个文件描述符(这一个套接字是完成具体业务的),接收失败则返回 -1,并设置错误码

3. read 函数:读取文件(网络)中的内容

ps:tcp 是面向流的,可以用;udp 是面向数据报的,不可以用

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

返回值:

  • 成功返回读取到的字符数,对方关闭连接返回 0,读取失败返回 -1,并设置错误码

4. write 函数:写入数据到文件(网络)

ps:tcp 是面向流的,可以用;udp 是面向数据报的,不可以用

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

返回值:

  • 成功返回写入的字符数,写入失败返回 -1,并设置错误码

5. connect 函数:发起链接请求 (TCP, 客户端)

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

参数 sockfd:

  • 发起连接的套接字的文件描述符

参数 addr:

  • 记录要发送对象的信息缓冲区,转成 (struct sockaddr *) 可以使用

参数 addrlen:

  • 缓冲区的大小

返回值:

  • 成功返回 0,失败返回 -1,并设置错误码

6. recv 函数:接收来自套接字的信息

使用和 read 几乎一样。

#include <sys/types.h>         
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags);  

参数 sockfd:

  • 服务端所绑定的套接字,后续接收和访问都从这里来

参数 buf:

  • 未来读到的数据要放在哪一个用户或者缓冲区里

参数 len:

  • 缓冲区的长度

参数 flags:

  • 0,默认以阻塞方式读取

返回值:

  • 成功则返回接收的字节数,失败返回 -1 并设置错误码
更多推荐

解决方案| anyRTC远程检修应用场景

背景在这个科技飞速发展的时代,各行各业都要求高效运转。然而,当出现问题时,我们却常常因为无法及时解决而感到困扰,传统解决问题的方式是邀请技术人员现场解决问题,如果技术人员解决不了,还要邀请专家从其他城市到现场解决,这中间会流失很多时间,影响生产效率。现在,anyRTC推出一站式远程检修方案,让检修得到最专业、最快速的的

el-select 下拉框全选、多选的几种方式组件

组件一、基础多选适用性较广的基础多选,用Tag展示已选项<template><el-selectv-model="value1"multipleplaceholder="请选择"><el-optionv-for="iteminoptions":key="item.value":label="item.label":va

windows批处理 将当前路径添加到Windows的`PATH`环境变量中 %~dp0

将当前路径添加到Windows的PATH环境变量中要将当前路径添加到Windows的PATH环境变量中,可以使用以下方法:使用命令行:打开命令提示符(CommandPrompt)或PowerShell,然后执行以下命令:setxPATH"%PATH%;C:\Your\Current\Directory"这会将当前路径(

【面试刷题】——C++四种类型转化

C++支持多种类型转换操作,其中包括四种主要类型转换方式:隐式类型转换(ImplicitConversion):隐式类型转换是自动发生的类型转换,由编译器自动完成。它用于处理不同数据类型之间的运算,例如将整数和浮点数相加时,整数会隐式地转换为浮点数。例如,将int转换为double或将float转换为int都是隐式类型

LinuxShell命令行及脚本编程实例详解_笔记

LinuxShell命令行及脚本编程实例详解Linux典藏大师系列丛书shell脚本的构成:1.shell关键字if...thenelse;for...done;whiledodone2.shell命令export,echo,exit,pwd,return3.linux命令datarmmkdircd4.文本处理功能aw

39 | selenium基础架构,UI测试架构

什么是测试基础架构?测试基础架构指的是,执行测试的过程中用到的所有基础硬件设施以及相关的软件设施。因此,我们也把测试基础架构称之为广义的测试执行环境。通常来讲,测试基础架构主要包括以下内容:执行测试的机器;测试用例代码仓库;发起测试执行的JenkinsJob;统一的测试执行平台;测试用例执行过程中依赖的测试服务,比如提

百望云获评ITShare数智未来创新峰会“年度数字化优秀服务商”大奖

近日,百望云应邀出席“新能源-新制造暨汽车数智未来创新峰会”,凭借在数字化领域优秀的服务能力和丰富的落地成果,成功获评“年度数字化优秀服务商”,这也是市场对百望云在赋能企业数字化转型和产品创新领域的再度认可!在“数智创新未来”的主题下,百望云也与众多行业知名企业分享了财税数字化转型成功经验,共襄盛会,齐瞻未来。数智未来

【Linux】Linux权限

目录一、认识Linux下的用户分类1.root和普通用户是怎样切换的如果我是普通用户,那我怎么变成root?如果我是root,那我怎么变成指定的普通用户?2.对某一指令进行暂时提权二、什么叫做权限三、没有权限的会出现什么现象三、修改权限通过二进制序列转换对权限进行加减修改文件所属组、拥有者其他问题1.为什么我们创建文件

【计算机网络】75 张图详解:网络设备、网络地址规划、静态路由(万字长文)

75张图详解:网络设备、网络地址规划、静态路由1.网络设备1.1交换机1.2路由器2.网络地址规划2.1IP地址2.2分类地址2.3子网掩码2.4无类地址2.5子网划分2.5.1示例一2.5.2示例二2.6超网合并3.静态路由3.1路由表3.2直连路由3.3静态路由3.4默认路由3.5网关和默认网关4.实战演练4.1静

网络爬虫——HTTP和HTTPS的请求与响应原理

目录一、HTTP的请求与响应二、浏览器发送HTTP请求的过程三、HTTP请求方法四、查看网页请求五、常用的请求报头六、服务端HTTP响应七、常用的响应报头八、Cookie和Session九、响应状态码十、网页的两种加载方法十一、认识网页源码的构成十二、爬虫协议在如今这个数据驱动的时代,网络爬虫在数据采集、信息抓取和处理

【大数据开发技术】实验04-HDFS文件创建与写入

文章目录一、实验目标二、实验要求三、实验内容四、实验步骤一、实验目标熟练掌握hadoop操作指令及HDFS命令行接口掌握HDFS原理熟练掌握HDFS的API使用方法掌握单个本地文件写入到HDFS文件的方法掌握多个本地文件批量写入到HDFS文件的方法二、实验要求给出主要实验步骤成功的效果截图。要求分别在本地和集群测试,给

热文推荐