Linux网络编程 socket编程篇(一) socket编程基础

news2024/12/22 23:10:24

目录

一、预备知识 

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 理解源端口号和目的端口号

  • 传输层协议(TCPUDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号。 就是在描述 "数据是谁发的, 要发给谁"。
  • 源端口号:发送消息的进程的端口号。
  • 目的端口号:接收消息的进程的端口号。

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协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接字。

拓】网络套接字

  1. 流套接字(SOCK_STREAM)流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因TCP协议。流套接字只能读取TCP协议的数据
  2. 数据报套接字(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结构体指针做为参数。

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

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

相关文章

Qt通过QSS设置QPushButton的样式

同时设置QPushButton的文字样式和图标的方法 为了美化界面&#xff0c;有时候需要修改QPushButton的样式&#xff0c;让一个QPushButton上面既要显示图标&#xff0c;又要显示文字内容 起初我的做法是重写QPushButton&#xff0c;这样做可以实现&#xff0c;但是有几个问题 实现…

【数学建模】逻辑回归算法(Logistic Resgression)

逻辑回归算法 简介逻辑回归与条件概率绘制sigmoid函数 简介 逻辑回归算法是一种简单但功能强大的二元线性分类算法。需要注意的是&#xff0c;尽管"逻辑回归"名字带有“回归”二字&#xff0c;但逻辑回归是一个分类算法&#xff0c;而不是回归算法。 我认为&#xff…

通达OA SQL注入漏洞【CVE-2023-4165】

通达OA SQL注入漏洞【CVE-2023-4165】 一、产品简介二、漏洞概述三、影响范围四、复现环境POC小龙POC检测工具: 五、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损…

PHP最简单自定义自己的框架实现像TP链式sql语句(六)

1、实现效果&#xff0c;链式sql语句封装 order、where、group、limit等封装 2、数据表构造函数入参&#xff0c;ModelBase.php public $table NULL; public function __construct($table){$this->table$table;if(!$this->table){die("no table" );}$this-&…

C语言----输入scanf和输出printf详解

C语言编程中&#xff0c;输入输出是基本操作&#xff0c;printf和scanf并不是C语言中的唯一的输入输出选择&#xff0c;对于输入有scanf()、getchar()、getche()、getch()、gets()&#xff1b;对于输出有printf()、puts()、putchar()&#xff0c;他们各有自己的使用场景&#x…

C语言案例 阶乘求和-12

题目&#xff1a;求1 2&#xff01;3&#xff01; … 20&#xff01;的和。 程序分析 阶乘相关原理&#xff1a;一个正整数的阶乘是所有小于及等于该数的正整数的积&#xff0c;并且0的阶乘为1。自然数n的阶乘写作n!&#xff0c;任何大于1的自然数n阶乘表示方法&#xff1a;…

StarRocks入门部署

目录 一、StarRocks整体介绍 1.1、系统架构图&#xff1a; 1.2、FE相关 1.3、BE相关 1.4、数据管理特性 二、简单部署 2.1、部署前准备 2.2、手动部署 2.2.1、部署Leader FE节点 2.2.2、部署BE节点 2.2.3、关联FE、BE&#xff0c;搭建StarRocks集群 2.2.4、给root设…

【深度学习】日常笔记16

可以将pd.DataFrame数据结构理解为类似于Excel中的表格。pd.DataFrame是pandas库提供的一个二维数据结构&#xff0c;用于存储和操作具有行和列的数据。它类似于Excel中的工作表&#xff0c;其中每一列可以是不同的数据类型&#xff08;例如整数、浮点数、字符串等&#xff09;…

接口防护电路

一、接口电路是电路中与用户或者外界媒介进行交互的部分&#xff0c;是内部核心敏感电路和外部设备进行信息交互的桥梁。接口电路一般分为输入接口电路和输出接口电路两种。接口电路的防护设计就是为了隔离外部危险的信号&#xff0c;防止外部干扰信息进入系统内部核心敏感电路…

Linux系统USB转串口芯片 GPIO使用教程

一、简介 WCH的多款USB转单路/多路异步串口芯片&#xff0c;除串口接口以外&#xff0c;还提供独立的GPIO接口&#xff0c;各GPIO引脚支持独立的输出输入&#xff0c;GPIO功能的使用需要与计算机端厂商驱动程序和应用软件配合使用。各芯片的默认GPIO引脚状态有所区别&#xff…

Redis——常见数据结构与单线程模型

Redis中的数据结构 Redis中所有的数据都是基于key&#xff0c;value实现的&#xff0c;这里的数据结构指的是value有不同的类型。 当前版本Redis支持10种数据类型&#xff0c;下面介绍常用的五种数据类型 底层编码 Redis在实现上述数据结构时&#xff0c;会在源码有特定的…

RCNA——单臂路由

一&#xff0c;实验背景 之前的VLAN实现的很多都是相同部门互相访问&#xff0c;不同部门无法访问。不过这次整来了一个路由器&#xff0c;领导说大部分的部门虽说有保密信息需要互相隔离&#xff0c;但是这些部门和其它部门也应该互相连通以方便工作交流。因此要配置新的环境&…

2023-08-11 LeetCode每日一题(矩阵对角线元素的和)

2023-08-11每日一题 一、题目编号 1572. 矩阵对角线元素的和二、题目链接 点击跳转到题目位置 三、题目描述 给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1&#xff1…

linux安装ftp

一、安装 参考博客 https://blog.csdn.net/dafeigecsdn/article/details/126518069 rpm -qa |grep vsftpd # 查看是否安装ftp yum -y install vsftpd # 安装vsftpuseradd -d /home/lanren312 lanren312 # 指定在/home目录下创建用户 passwd lanren312 # 给用户设置密码 # 输…

2022年03月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;双精度浮点数的输入输出 输入一个双精度浮点数&#xff0c;保留8位小数&#xff0c;输出这个浮点数。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 只有一行&#xff0c;一个双精度浮点数。 输出 一行&#xff0c;保留8位小数的浮点数。 样例输…

【Unity每日一记】让一个物体按余弦曲线移动—(三角函数的简单运用)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

麻省理工学院利用水泥和炭黑制造出超级电容器

麻省理工学院的研究人员展示了一种使用低成本水泥和炭黑的制造的超级电容器&#xff0c;这一发明可能会彻底颠覆可再生能源的存储。 ​为了解决太阳能、风能和潮汐能等间歇性和非周期性电源的普及问题&#xff0c;实用并且廉价的电力储存技术一直是重要的环节。MIT的研究人员最…

从docker启动kali

前言: 偶然间在docker中发现有Linux的镜像&#xff0c;有了尝试的想法&#xff0c;于是有了本文 选了星星最多的那个&#xff0c;直接pull&#xff0c;或者命令行执行 docker run kalilinux/kali-rolling 介绍中说&#xff0c;没有任何工具&#xff0c;所以需要自己安装。 直接…

Jpa与Druid线程池及Spring Boot整合(二): spring-boot-starter-data-jpa 踏坑异常处理方案

Jpa与Druid线程池及Spring Boot整合(一) Jpa与Druid线程池及Spring Boot整合(二)&#xff1a;几个坑 附录官网文档&#xff1a;core.domain-events域事件 从聚合根发布事件 存储库管理的实体是聚合根。在领域驱动设计应用程序中&#xff0c;这些聚合根通常会发布领域事件。Sp…

Golang函数以及函数和方法的区别

在接触到go之前&#xff0c;我认为函数和方法只是同一个东西的两个名字而已&#xff08;在我熟悉的c/c&#xff0c;python&#xff0c;java中没有明显的区别&#xff09;&#xff0c;但是在golang中者完全是两个不同的东西。官方的解释是&#xff0c;方法是包含了接收者的函数。…