Linux网络编程 socket编程篇(一) socket编程基础
目录
一、预备知识
1.IP地址
2.端口号
3.网络通信
4.TCP协议简介
5.UDP协议简介
6.网络字节序
二、socket
1.什么是socket(套接字)?
2.为什么要有套接字?
3.套接字的主要类型
拓】网络套接字
三、socket API
1.socket API是什么?
2.为什么要有Socket API?
3.Socket编程常见API
3.1 socket()
int socket(int domain, int type, int protocol);
3.2 bind()
3.3 listen ()
3.4 accept()
3.5 connect ()
四、sockaddr
1. 是什么?
2. 为什么?
3. sockaddr的分类
4.Linux中sockaddr的声明
5.创建并填充struct sockaddr_in
6.使用sockaddr传参
一、预备知识
1.IP地址
1.1 是什么?
IP地址是在IP协议中, 用来标识网络中不同主机的地址。
1.2 IPv4 & IPv6
- 对于IPv4来说, IP地址是一个4字节, 32位的整数。通常使用 "点分十进制" 的字符串表示IPv4地址, 例如 123.145.67.89 ; 用点分割的每一个数字表示一个字节, 范围是 0 - 255;
- 对于IPv6来说, IP地址长度为16字节128位,是IPv4地址长度的4倍。于是IPv4点分十进制格式不再适用,采用十六进制表示。具体表示方式请看:IPv6- 百度百科
1.3源IP和目的IP
- 在IP数据报(在网络层向数据链路层传递数据时封装)的首部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址。
- 源IP地址:发送消息的主机地址。
- 目的IP地址:接收消息的主机地址。
2.端口号
2.1 是什么?
端口号是一个2字节16位的整数,用来标识一个进程。
2.2 pid 表示唯一一个进程; 端口号也是唯一表示一个进程. 那么这两者之间是怎样的关系?
- "端口号" 和 "进程pid"没有任何关系。
端口号用于网络通信,而进程pid用于进程管理,网络通信和进程管理是两个毫不相干的模块。之所以不用pid来代替端口号的功能是为了功能解耦,减少系统的耦合度。- 不是所有的进程需要端口号,但是所有的进程都需要PID。
- 一个进程可以有多个端口号; 但一个端口号只能被一个进程占用。
2.3 理解源端口号和目的端口号
- 传输层协议(TCP和UDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号。 就是在描述 "数据是谁发的, 要发给谁"。
- 源端口号:发送消息的进程的端口号。
- 目的端口号:接收消息的进程的端口号。
3.网络通信
3.1 是什么?
网络通信的本质就是进程间通信。
3.2 为什么?
发送数据的主机由进程发出数据,接收数据的主机也要靠进程处理数据。简化后其实就是一个进程发出数据,另一个进程处理数据。所以说网络通信的本质就是进程间通信。
3.3 网络通信时如何保证IP地址+端口号能找到指定进程?
- 客户端进程给服务端进程发信息
服务端进程一般都是一经启动,避免关闭,所以服务端进程的端口号不会随意改变。所以客户端进程能根据下载软件时得到的IP地址+端口号找到服务端进程。- 服务端进程给客户端进程发信息
软件被用户打开后,客户端进程和端口号被创建,此时客户端进程要先向服务端发信息来获取数据,所以服务端进程就得到了客户端进程的IP地址+端口号,往后服务端进程能根据客户端进程的IP地址+端口号找到客户端进程。(所以我们打开软件后,通常会加载一会)
3.4 OS如何根据端口号找到指定的进程?
底层采用哈希的方式建立了端口号和进程PID或PCB之间的映射关系,当底层拿到端口号时就可以在哈希表中根据端口号找到对应的进程。
3.5 网络通信是双方的
当一台主机发送数据给另一台主机时,发送方除了要发送数据外还要把自己的 IP地址和端口号 发送给接收方,所以接收方能给发送方回数据。所以说通信是双方的。
4.TCP协议简介
- TCP(Transmission Control Protocol 传输控制协议),TCP协议是一种有连接、可靠、面向字节流的传输层通信协议。
- TCP协议是面向连接的,如果两台主机之间想要进行数据传输,那么必须要先建立连接,当连接建立成功后才能进行数据传输。
- TCP协议是可靠的,因为TCP协议注重丢包率, TCP协议花费大量开销解决数据在传输过程中出现的丢包、乱序等问题,保证不丢包。文件传输、电子邮件、网站访问一般用的就是TCP协议。
5.UDP协议简介
- UDP(User Datagram Protocol 用户数据报协议),UDP协议是一种无连接、不可靠、面向数据报的传输层通信协议。
- 使用UDP协议进行通信时无需建立连接,如果两台主机之间想要进行数据传输,那么直接将数据发送给对端主机就行了。
- UDP协议是不可靠的,因为UDP协议注重效率,没有处理在传输数据过程中小概率出现的丢包、乱序等情况。直播一般用的就是UDP协议。
6.网络字节序
6.0 大端字节序和小端字节序
- 大端字节序:是将数据的低位字节放到高地址处,高位字节放到低地址处。
(大端低地址高字节:“大弟高”)
- 小端字节序,是将数据的低位字节放到低地址处,高位字节放到高地址处。
(小端低地址低字节:“小弟弟”)
6.1 是什么?
即网络通信中共同遵守的字节序,规定为 大端字节序(低字节,高地址)。
6.2 为什么?
不同计算机的 字节序不同,如果在网络通信时不加以规定,会出现发送方以大端模式发送数据,接收方以小端模式读取数据,导致通信失败的情况。
6.3 怎么定义?
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据。如果当前发送主机是小端, 就需要先将数据转成大端再发送,否则直接发送。
6.4 网络字节序与主机字节序之间的转换函数
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换
#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong); //将主机字节序(h)转换为(to)网络字节序(n)要转化的数据是长整数(l)。uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
- 这些函数名很好记:h表示host,n表示network,l表示32位长整数,s表示16位短整数。所以htonl表示:将主机字节序(h)转换为(to)网络字节序(n)要转化的数据是长整数(l)。
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回。
- 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。
二、socket
1.什么是socket(套接字)?
IP地址+端口号就是socket(套接字) ,用来标定某主机上的某进程。
2.为什么要有套接字?
有了套接字,不同主机的进程才能在网络中找到彼此,才能进行网络通信(进程间通信的前提是能互相看到彼此),所以说套接字是网络通信的基石。其次有了套接字,开发者才能开发出通用的网络通信接口,用户也能拿着套接字去使用这些接口。
3.套接字的主要类型
- 网络套接字:应用于跨主机网络通信,也支持本地通信,主要有两种:
a.流套接字:用于读取TCP协议的数据。
b.数据报套接字:用于读取UDP协议的数据。- unix域间套接字:只能进行本地通信。
- 原始套接字(SOCK_RAW):可以从应用层直接绕开传输层,直接去访问底层协议,所以原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接字。
拓】网络套接字
- 流套接字(SOCK_STREAM)流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因TCP协议。流套接字只能读取TCP协议的数据。
- 数据报套接字(SOCK_DGRAM)数据报套接字提供一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP( User DatagramProtocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。数据报套接字只能读取UDP协议的数据。
拓】功能强大的套接字
套接字是非常强大的,虽然现在主要用于网络通信,但其实套接字可以用于几乎任何类型的进程间通信:本地通信、各种类型的网络通信等。
三、socket API
1.socket API是什么?
是提供给程序员(应用层)做网络开发所用的接口,用来实现不同主机中进程的通信。
Socket API(套接字编程接口)实际是 传输层 提供给 应用层 的编程接口,用来实现不同主机中进程的通信:传输层在网络层的基础上提供进程到进程问的逻辑通道,而应用层的进程则利用传输层向另一台主机的某一进程通信。Socket就是应用层与传输层之间的桥梁,使用Socket编程可以开发客户端和服务端应用程序,从而通过网络实现在全球范围内通信。
2.为什么要有Socket API?
socket(套接字)只是网络通信的前提,只有开发出一套通用的网络接口才能实现不同主机中进程的通信。Linux下的这套接口就是Socket API(套接字编程接口)。
3.Socket编程常见API
3.1 socket()
int socket(int domain, int type, int protocol);
//创建socket_fd(套接字 文件描述符),用于TCP/UDP网络程序中的客户端 + 服务器![]()
3.2 bind()
//让 socket_fd和sockaddr_in绑定, 用于 TCP/UDP 网络程序中的 服务器。![]()
3.3 listen ()
//开始监听socket,用于 TCP 网络程序中的 服务器
3.4 accept()
//接收请求,用于 TCP 网络程序中的 服务器
3.5 connect ()
//建立连接,用于 TCP 网络程序中的 服务器
四、sockaddr
1. 是什么?
struct sockaddr(套接字地址结构体)是Linux用来保存套接字和套接字类型的结构体。
2. 为什么?
使用Socket API要需要传入套接字,Linux选择用struct sockaddr保存套接字和套接字类型。在Linux下使用Socket API要传入struct sockaddr*。
3. sockaddr的分类
Linux中只设置了一套Socket API(套接字编程接口),但是有不同类型的套接字(用于IPv4的套接字、用于IPv6的、用于本地通信的) ,所以使用struct sockaddr、struct sockaddr_in 、struct sockaddr_un来区分不同类型的套接字:
sockaddr、sockaddr_in 和 sockaddr_un结构体头部的16个比特位(2字节)都是一样的,这16位是地址类型用来区分套接字的类型的,根据套接字的类型(IPv4、IPv6……),分别定义为常数AF_INET、AF_INET6……
Socket API都用struct sockaddr *类型传参,将 sockaddr_in 或 sockaddr_un强制类型转换为sockaddr,才能被Socket API识别。对于传进来的参数 sockaddr ,函数通过前两个字节,进行判断是网络通信还是本地通信,知道这个结果后再强制类型转换回 sockaddr_in 和 sockaddr_un结构体。这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。
4.Linux中sockaddr的声明
- struct sockaddr(在头文件:<sys/socket.h>中)
- struct sockaddr_in (在头文件:<netinet/in.h>中)
- struct sockaddr_un (在头文件:<sys/un.h>中)
5.创建并填充struct sockaddr_in
4.0 导入结构体定义所在的头文件。
#include <netinet/in.h>
struct sockaddr_in ,定义在头文件:<netinet/in.h>中。
4.1 定义struct sockaddr_in变量。
struct sockaddr_in local;
- struct sockaddr_in:用来定义Ipv4和Ipv6的套接字结构体,用于网络通信。
- struct sockaddr_un :用来定义UNIX_Domain_Socket(Unix域套接字:用于同一台主机上进程间通信)。用于本地通信。
4.2 初始化结构体
bzero(&local, sizeof(local));
使用bzero() 或 memset()初始化结构体的内存空间为0 。
4.3 设置地址类型
local.sin_family = AF_INET;
4.4 设置端口号 (保存端口号的变量为:port,是一个2字节16位的整数)
local.sin_port = htons(port);
端口号要被对方获取,也是网络数据的一部分,所以要考虑大小端问题,使用htons函数将主机字节序转为网络字节序。
4.5 设置IP地址 (保存IP地址的变量为:ip,是一个点分十进制字符串)
local.sin_addr.s_addr = inet_addr(ip);
inet_addr()的作用:
1.将点分十进制字符串风格的IP地址 -> 4字节整数
2.ip地址也要考虑大小端:将4字节整数 -> 网络序列
6.使用sockaddr传参
Socket API只接受struct sockaddr *类型传参,所以将 sockaddr_in、 sockaddr_un强制类型转换为sockaddr,才能被Socket API识别。
对于传进来的参数 sockaddr ,函数通过前两个字节,进行判断是网络通信还是本地通信,知道这个结果后再强制类型转换回 sockaddr_in 和 sockaddr_un结构体。这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。
相关文章:

Linux网络编程 socket编程篇(一) socket编程基础
目录 一、预备知识 1.IP地址 2.端口号 3.网络通信 4.TCP协议简介 5.UDP协议简介 6.网络字节序 二、socket 1.什么是socket(套接字)? 2.为什么要有套接字? 3.套接字的主要类型 拓】网络套接字 三、socket API 1.socket API是什么? 2.为什么…...

【二】SPI IP核的使用
【一】SPI IP核使用:传送门 基于qsys通过spi外部总线协议对sd卡进行读写操作 一、实验平台与实验的目的: 正点原子开拓者、芯片型号:EP4CE10F17C8;还需要一张sd卡。 该实验主要是利用SPI IP核驱动SD卡来实现读写实验&am…...

面试热题(二叉树的锯齿形层次遍历)
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行) 输入:root [3,9,20,null,null,15,7] 输出:[[3…...

JVM—内存管理(运行时数据区)、垃圾回收
背景介绍 当JVM类加载器加载完字节码文件之后,会交给执行引擎执行,在执行的过程中会有一块JVM内存区域来存放程序运行过程中的数据,也就是我们图中放的运行时数据区,那这一块运行时数据区究竟帮我们做了哪些工作?我们…...

一百五十一、Kettle——Linux上安装的kettle8.2开启carte服务
一、目的 kettle8.2在Linux上安装好可以启动界面、并且可以连接MySQL、Hive、ClickHouse等数据库后,准备在Linux上启动kettle的carte服务 二、实施步骤 (一)carte服务文件路径 kettle的Linux运行的carte服务文件是carte.sh (二…...

19. python从入门到精通——Web编程
HTTP协议 HTTP协议的常用方法 方法 描述 GET 请求指定的页面信息,并返回实体主体。 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 …...
PostMan 教程
安装https://www.cnblogs.com/mafly/p/postman.html Postman 使用方法详解https://blog.csdn.net/fxbin123/article/details/80428216 postman进行http接口测试https://blog.csdn.net/five3/article/details/53021084 postman的使用方法详解!最全面的教程https:/…...
Http常见状态码
一、状态码大类 状态码分类说明1xx响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它2xx成功——表示请求已经被成功接收,处理已完成3xx重定向——重定向到其它地方:它让客户端再发起一个…...

C语言之位运算
一、什么是位运算 所谓位运算是指进行二进制位的运算 在系统软件中,常要处理二进位的问题 例如,将一个存储单元中的各二进位左移或右移一位,两个数按位相加等 二、位运算符和位运算 1、按位与 运算符(&) 参加运算的两个数据ÿ…...

c语言进阶部分详解(数据在内存中的存储)
大家好,今天要进行梳理的内容是数据在内存中的存储相关内容。 在C语言中,数据在内存中的存储是一个非常重要的概念。了解数据在内存中的存储方式可以帮助我们更好地理解程序的执行过程,优化内存使用,提高程序的性能。 目录 一.数…...

VIOOVI的ECRS工时分析软件分析:SOP的核心和特征是什么?
制定SOP的主要目的是为企业做技术储备、提供企业的工作效率、防止同样的错误反复出现、让员工作业有标准化的行为准则。以规定的成本、规定的工作时间,生产质量均匀、符合规范的产品。为了能够达到上述要求,如果制造现场的操作混乱,比如制作工…...

无涯教程-Perl - lock函数
描述 此函数将咨询锁放在共享变量或THING中包含的引用对象上,直到该锁超出范围。 lock()是一个"弱关键字":这意味着,如果您在调用该函数之前已通过该名称定义了该函数,则将改为调用该函数。 语法 以下是此函数的简单语法- lock THING返回值 此函数不返回任何值…...
SpringBoot案例-部门管理-前后端联调
前后端联调 教学资料中提供了“前端工程”,将其解压即可使用nginx,启动nginx后,访问:http://localhost:90 小结 开发流程 明确需求、阅读接口文档、思路分析、接口开发(遵循接口文档)接口调试 postman测…...

每天一道leetcode:139. 单词拆分(动态规划中等)
今日份题目: 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例1 输入: s "leetcode", …...
【C++】友元(含内部类)
一、友元是什么 我把你添加为我的友元,那么你可以访问我的成员。特别注意:它是单向的。即,我把你添加为我的友元,我却不能访问你的成员,除非你把我添加为你的友元。 以下代码可以让你粗略了解友元的使用。 #includ…...

SQL | 检索数据
1-检索数据 1.1-检索单个列 SELECT prod_name FROM Products; 上述SELECT语句从Products表中检索一个名为prod_name的列。 所要查找的列在select后面,from关键字指出从那个表查询数据。 输出如下: prod_name8 inch teddy bear12 inch teddy bear18…...
typeScript 之 运算符
工具: PlayGround 算术运算符 运算符描述加-减*乘/除%取模(求余)自增–自减 注意和--,实例: let value 0; console.log(value); //0, 先显示再增加后为1 console.log(value); //2,先增加后为2再显示关系运算符 运算符描述 …...

BGP实验
题目 IP地址配置 172.16.X.0/24为模拟用户环回接口接口 172.16.7.X/32为BGP邻居关系建立的环回接口 R1: R2: R3: R4: R5: R6: R7: R8: BGP邻居关系建立、宣告和反射器、联邦配置 R…...

pytest fixture 常用参数
fixture 常用的参数 参数一:autouse,作用:自动运行,无需调用 举例一:我们在类中定义一个function 范围的fixture; 设置它自动执行autouseTrue,那么我们看下它执行结果 输出: 说明:…...

vue项目里面有多个模块的服务,前端处理url转发
先看下vue的代理配置里面: 现在是在 /pca 基础上增加了 2个模块的服务: /dca、 /api 现在服务器的nginx 没有在/pca 服务里面做转发接受 /dca、 /api的服务,所以需要前端自己去配置每个服务模块对应的 URL 先拿登录的api 做示例吧: 先定义…...
十八、【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案
【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案 前言什么是 JWT (JSON Web Token)?准备工作第一部分:后端 Django 配置 JWT 认证1. 安装 `djangorestframework-simplejwt`2. 在 `settings.py` 中配置 `djangorestframework-simplejwt`3. 在项目的 `urls.py` 中添加…...
Cisco IOS XE WLC 任意文件上传漏洞复现(CVE-2025-20188)
免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 前…...

若依框架修改模板,添加通过excel导入数据功能
版本:我后端使用的是RuoYi-Vue-fast版本,前端是RuoYi-Vue3 需求: 我需要每个侧边栏功能都需要具有导入excel功能,但是若依只有用户才具备,我需要代码生成的每个功能都拥有导入功能。 每次生成一个一个改实在是太麻烦了。索性…...
第6篇:中间件 SQL 重写与语义分析引擎实现原理
6.1 章节导读 SQL 是数据库中间件的“输入语言”。 在一个真正强大的中间件系统中,SQL 语句的执行通常不再是“原封不动”地传递给数据库,而是需要先经过: 语义分析:解析 SQL 的结构和含义。 SQL 重写:根据中间件逻辑…...

基于SpringBoot的“嗨玩旅游”网站设计与实现(源码+定制+开发)嗨玩旅游平台开发:景点展示与个性化推荐系统(SpringBoot)
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
Android 11以上App主动连接WIFI的完整方案
早期Android版本App内连接指定的WIFI还是比较简单的,但是随着Android版本的提升,限制也越来越多。以下是一套完整的Android 11以上的WIFI应用内主动连接方案。 第一步:添加到建议连接: val wifiManager getSystemService(WIFI_…...

每日一C(1)C语言的内存分布
目录 代码区 常量区 全局/静态区 初始化数据段(.data) 未初始化数据段(.bss) 堆区 栈区 总结 今天我们学习的是C语言的内存分布,以及这些分区所存储的内容和其特点。今天的思维导图如下。 C语言作为一款直接处…...

【Linux】进程 信号保存 信号处理 OS用户态/内核态
🌻个人主页:路飞雪吖~ 🌠专栏:Linux 目录 一、信号保存 ✨进程如何完成对信号的保存? ✨在内核中的表示 ✨sigset_t ✨信号操作函数 🪄sigprocmask --- 获取或设置当前进程的 block表 🪄s…...
Vue-1-前端框架Vue基础入门之一
文章目录 1 Vue简介1.1 Vue的特性1.2 Vue的版本2 Vue的基础应用2.1 Vue3的下载2.2 Vue3的新语法2.3 vue-devtools调试工具3 Vue的指令3.1 内容渲染指令{{}}3.2 属性绑定指令v-bind3.3 事件绑定指令v-on3.4 双向绑定指令v-model3.5 条件渲染指令v-if3.6 列表渲染指令v-for4 参考…...

嵌入式系统中常用的开源协议
目录 1、GNU通用公共许可证(GPL) 2、GNU宽松通用公共许可证(LGPL) 3、MIT许可证 4、Apache许可证2.0 5、BSD许可证 6、如何选择合适的协议 在嵌入式系统开发中,开源软件的使用已成为主流趋势。从物联网设备到汽车…...