socket地址理解

news2024/10/7 14:26:46

socket介绍

套接字的基本概念

1. 套接字的定义:

  • 套接字(socket)是计算机网络中用于通信的端点,它抽象了不同主机上应用进程之间双向通信的机制。

2. 套接字的作用:

  • 套接字连接应用进程与网络协议栈,使得应用程序能够利用网络协议进行通信。
  • 它作为应用程序与网络协议栈的接口,通过操作系统提供的 API 进行数据交换。
套接字的工作机制

1. 双向通信:

  • 在网络通信中,套接字充当两个应用程序之间的通信连接点。
  • 一个应用程序可以将数据写入其所在主机的套接字,数据通过网络接口卡(NIC)和传输介质发送到目标主机的套接字,从而实现数据传输。

2. 组合与寻址:

  • 套接字由 IP 地址和端口号组成,形成唯一的通信端点。
  • 这种组合提供了一种机制,使数据包能够准确地传输到目标应用进程。

套接字在操作系统中的表示

1. 套接字作为文件:

  • 在 Linux 环境下,套接字是一种特殊的文件类型,被内核用伪文件(pseudo-file)表示。
  • 由于套接字被视为文件,因此可以使用文件描述符来引用和操作套接字。
  • 这种设计使得套接字的读写操作与普通文件的读写操作一致,统一了接口。

2. 区别于管道:

  • 虽然套接字与管道(pipe)类似,都用于进程间通信,但套接字主要用于网络进程间的数据传递,而管道主要用于本地进程间的通信。

套接字的类型

1. 常见的套接字类型:

  • 流式套接字(Stream Socket):提供面向连接的、可靠的数据传输服务,典型的协议是 TCP。
  • 数据报套接字(Datagram Socket):提供无连接的、不可靠的数据传输服务,典型的协议是 UDP。
总结

套接字是网络编程中的核心概念,提供了在不同主机上的应用进程之间进行通信的机制。它通过 IP 地址和端口号进行唯一标识,并在操作系统中作为特殊的文件类型进行管理,使得网络通信操作与文件操作一致,从而简化了编程接口。

socket 本身有“插座”的意思,在 Linux 环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux 系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传 递。

image-20240522062732723

// 套接字通信分两部分:

- 服务器端:被动接受连接,一般不会主动发起连接

- 客户端:主动向服务器发起连接

socket是一套通信的接口,Linux 和 Windows 都有,但是有一些细微的差别。

字节序

字节序(Endian)问题是计算机系统中关于数据表示的重要概念,主要涉及到数据的存储和通信方式。在不同的计算机体系结构中,字节序可能不同,这就要求在进行数据传输和通信时必须明确字节序,以确保数据正确地被解释和处理。

大端字节序(Big-Endian)

大端字节序,也称为“网络字节序”,因为它是多数网络协议采用的字节序,包括TCP/IP。在大端字节序中,一个多字节数值的最高字节(即最重要的字节)被存储在最低的内存地址,其次是次高字节,依此类推。例如,一个32位整数0x12345678在内存中的存储方式如下(地址由低到高):

  • 地址 x + 0: 0x12
  • 地址 x + 1: 0x34
  • 地址 x + 2: 0x56
  • 地址 x + 3: 0x78
小端字节序(Little-Endian)

记忆:小低低

小端字节序则恰好相反,一个多字节数值的最低字节(即最不重要的字节)被存储在最低的内存地址。它被很多现代桌面计算机体系(如x86架构)采用。例如,同样的32位整数0x12345678在小端字节序的计算机中的存储方式如下:

  • 地址 x + 0: 0x78
  • 地址 x + 1: 0x56
  • 地址 x + 2: 0x34
  • 地址 x + 3: 0x12
字节序的重要性

在网络通信中,字节序的不一致会导致数据被错误解释,进而造成通信错误。因此,为了数据能在不同的计算机系统间正确传输和接收,往往需要在发送和接收端之间进行字节序的转换。例如,在一个小端字节序的机器上发送数据到一个大端字节序的机器上时,发送者需要将数据从小端转换为大端字节序。

在进行网络编程,尤其是跨平台通信时,理解并正确处理字节序问题是非常关键的。Socket编程中经常用到的htonl()ntohl()等函数就是用于在主机字节序和网络字节序之间转换整数的字节序。

总结来说,字节序是一个基础而重要的概念,涉及到计算机体系、操作系统平台、网络通信等多个层面,正确处理字节序问题对保证数据交换的正确性和效率至关重要。

image-20240522070409611

image-20240522070418150

案例
/*  
    字节序:字节在内存中存储的顺序。
    小端字节序:数据的高位字节存储在内存的高位地址,低位字节存储在内存的低位地址
    大端字节序:数据的低位字节存储在内存的高位地址,高位字节存储在内存的低位地址
*/

// 通过代码检测当前主机的字节序
#include <stdio.h>

int main() {

    union {
        short value;    // 2字节
        char bytes[sizeof(short)];  // char[2]
    } test;

    test.value = 0x0102;
    if((test.bytes[0] == 1) && (test.bytes[1] == 2)) {
        printf("大端字节序\n");
    } else if((test.bytes[0] == 2) && (test.bytes[1] == 1)) {
        printf("小端字节序\n");
    } else {
        printf("未知\n");
    }

    return 0;
}
daic@daic:~/Linux/linuxwebserver/part04networkProgramming$ gcc byteorder.c 
daic@daic:~/Linux/linuxwebserver/part04networkProgramming$ ./a.out 
小端字节序

在进行网络编程时,处理字节序是保证跨平台数据通信正确性的一个重要方面。你已经很好地概括了如何利用大端字节序(即网络字节序)来实现数据的一致性和正确传输。下面我们详细解释这些概念和具体的函数使用:

字节序转换函数

网络字节序的重要性

**网络字节序是大端(Big-Endian)字节序,**这意味着数据的高位字节存储在低地址上。TCP/IP 协议族规定使用大端字节序是为了确保数据在不同计算架构的机器间传输时,每一台设备都能以相同的方式解释这些数据。这个标准化的处理方式避免了每个应用程序需要考虑目标机器字节序的复杂性。

h - host 主机,主机字节序
to - 转换成什么
n - network 网络字节序
s - short unsigned short
l - long unsigned int
#include <arpa/inet.h>
// 转换端口
uint16_t htons(uint16_t hostshort); // 主机字节序 - 网络字节序
uint16_t ntohs(uint16_t netshort); // 主机字节序 - 网络字节序
// 转IP
uint32_t htonl(uint32_t hostlong); // 主机字节序 - 网络字节序
uint32_t ntohl(uint32_t netlong); // 主机字节序 - 网络字节序
字节序转换函数

BSD Socket API 提供了一些函数来帮助程序员在主机字节序和网络字节序之间转换数据。主要的函数有:

  • htonl() (Host TO Network Long): 将一个长整型数从主机字节序转换到网络字节序。
  • htons() (Host TO Network Short): 将一个短整型数从主机字节序转换到网络字节序。
  • ntohl() (Network TO Host Long): 将一个长整型数从网络字节序转换到主机字节序。
  • ntohs() (Network TO Host Short): 将一个短整型数从网络字节序转换到主机字节序。
使用场景
  • 发送数据时: 在发送数据之前,数据需要从主机字节序转换为网络字节序,使用 htonl()htons()
  • 接收数据时: 在读取从网络接收的数据时,需要将数据从网络字节序转换回主机字节序,使用 ntohl()ntohs()
示例

假设您正在编写一个跨平台的网络应用,您需要发送一个整数和一个短整型数:

#include <stdio.h>
#include <netinet/in.h>

int main() {
    int num = 0x12345678;
    short s_num = 0x1234;

    // 转换为网络字节序
    int net_num = htonl(num);
    short net_s_num = htons(s_num);

    // 发送 net_num 和 net_s_num ...
    
    // 接收数据
    // 假设接收到的数据存储在变量 net_num 和 net_s_num 中
    int host_num = ntohl(net_num);
    short host_s_num = ntohs(net_s_num);

    printf("Original: %x, Received: %x\n", num, host_num);
    printf("Original Short: %x, Received Short: %x\n", s_num, host_s_num);

    return 0;
}

这个例子展示了如何在发送和接收数据时处理字节序问题,确保数据在不同系统间正确地传输和解释。通过这种方式,无论数据是在小端还是大端机器上生成或接收的,都能正确处理,从而实现真正的跨平台兼容性。

案例
/*

    网络通信时,需要将主机字节序转换成网络字节序(大端),
    另外一段获取到数据以后根据情况将网络字节序转换成主机字节序。

    // 转换端口
    uint16_t htons(uint16_t hostshort);		// 主机字节序 - 网络字节序
    uint16_t ntohs(uint16_t netshort);		// 主机字节序 - 网络字节序

    // 转IP
    uint32_t htonl(uint32_t hostlong);		// 主机字节序 - 网络字节序
    uint32_t ntohl(uint32_t netlong);		// 主机字节序 - 网络字节序

*/

#include <stdio.h>
#include <arpa/inet.h>

int main() {

    // htons 转换端口
    // typedef unsigned short int __uint16_t;
    uint16_t a = 0x0102;
    printf("a : %x\n", a);
    unsigned short b = htons(a);
    printf("b : %x\n", b);

    printf("=======================\n");

    // htonl  转换IP
    char buf[4] = {192, 168, 1, 100};
    int num = *(int *)buf;
    int sum = htonl(num);
    unsigned char *p = (char *)&sum;

    printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));

    printf("=======================\n");

    // ntohl
    unsigned char buf1[4] = {1, 1, 168, 192};
    int num1 = *(int *)buf1;
    int sum1 = ntohl(num1);
    unsigned char *p1 = (unsigned char *)&sum1;
    printf("%d %d %d %d\n", *p1, *(p1+1), *(p1+2), *(p1+3));
    
     // ntohs


    return 0;
}
daic@daic:~/Linux/linuxwebserver/part04networkProgramming$ gcc bytetrans.c 
daic@daic:~/Linux/linuxwebserver/part04networkProgramming$ ./a.out 
a : 102
b : 201
=======================
100 1 168 192
=======================
192 168 1 1

socket地址

// socket地址其实是一个结构体,封装端口号和IP等信息。后面的socket相关的api中需要使用到这个
socket地址。
// 客户端 -> 服务器(IP, Port)
通用 socket 地址

socket 网络编程接口中表示 socket 地址的是结构体 sockaddr,其定义如下:

#include <bits/socket.h>
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
};
typedef unsigned short int sa_family_t;

sa_family 成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。常见的协议族(protocol family,也称 domain)和对应的地址族入下所示:

image-20240522080913698

sa_data 成员用于存放 socket 地址值。但是,不同的协议族的地址值具有不同的含义和长度,如下所示:

image-20240522081113172

由上表可知,14 字节的 sa_data 根本无法容纳多数协议族的地址值。因此,Linux 定义了下面这个新的通用的 socket 地址结构体,这个结构体不仅提供了足够大的空间用于存放地址值,而且是内存对齐的。

#include <bits/socket.h>
struct sockaddr_storage
{
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[ 128 - sizeof(__ss_align) ];
};
typedef unsigned short int sa_family_t;
专用 socket 地址

很多网络编程函数诞生早于 IPv4 协议,那时候都使用的是 struct sockaddr 结构体,为了向前兼容,现 在sockaddr 退化成了(void *)的作用,传递一个地址给函数,至于这个函数是 sockaddr_in 还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。

image-20240522104145742

UNIX 本地域协议族使用如下专用的 socket 地址结构体:

#include <sys/un.h>
struct sockaddr_un
{
sa_family_t sin_family;
char sun_path[108];
};

TCP/IP 协议族有 sockaddr_in 和 sockaddr_in6 两个专用的 socket 地址结构体,它们分别用于 IPv4 和

IPv6:

#include <netinet/in.h>
struct sockaddr_in
{
sa_family_t sin_family; /* __SOCKADDR_COMMON(sin_) */
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) - sizeof (struct in_addr)];
};


struct in_addr
{
in_addr_t s_addr;
};

struct sockaddr_in6
{
sa_family_t sin6_family;
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};

typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

所有专用 socket 地址(以及 sockaddr_storage)类型的变量在实际使用时都需要转化为通用 socket 地址类型 sockaddr(强制转化即可),因为所有 socket 编程接口使用的地址参数类型都是 sockaddr。

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

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

相关文章

加密与解密(第四版)】第二十五章笔记

第二十五章 数据取证技术 25.1 硬盘数据的获取和固定 取证专用的Linux可启动光盘 硬盘复制机 利用取证计算机复制硬盘 手机&#xff08;JTAG&#xff09; 电子数据的固定&#xff08;HASH值&#xff09; 25.2 硬盘的分区和数据恢复 25.3 内存分析 25.4 动态仿真技术 25.…

虚拟ECU:彻底改变汽车软件开发与测试

汽车开发领域有着垂直性较强的一系列需求&#xff0c;其中最为瞩目的需求之一就是对安全高效的软件测试方法的需求。传统的汽车开发偏向使用硬件原型与真实ECU进行软件测试&#xff0c;但由于硬件设备往往在开发周期的中后阶段才生产完成&#xff0c;给汽车开发带来了成本与时间…

做OZON怎么选择物流,OZON物流Xingyuan

随着跨境电商的蓬勃发展&#xff0c;OZON作为俄罗斯领先的电商平台&#xff0c;吸引了大量中国卖家入驻。然而&#xff0c;物流作为跨境电商的关键环节&#xff0c;其选择对于卖家来说至关重要。本文将围绕“做OZON怎么选择物流”这一问题&#xff0c;深度解析OZON物流Xingyuan…

二分查找

题目链接 题目: 分析: 如果按照从头到尾的顺序一次比较, 每次只能舍弃一个元素, 效率是非常低的, 而且没有用到题目的要求, 数组是有序的因为数组是有序的, 所以如果我们随便找到一个位置, 和目标元素进行比较, 如果大于目标元素, 说明该位置的右侧元素都比目标元素大, 都可…

内网穿透--Frp-简易型(速成)-上线

免责声明:本文仅做技术交流与学习... 目录 frp项目介绍: 一图通解: ​编辑 1-下载frp 2-服务端(server)开启frp口 3-kali客户端(client)连接frp服务器 4-kali生成马子 5-kali监听 6-马子执行-->成功上线 frp项目介绍: GitHub - fatedier/frp: A fast reverse proxy…

什么是智慧校园信息平台?

智慧校园信息渠道是以物联网、云核算、大数据分析等新技术为核心技术&#xff0c;为校园供给一种才智型、数据化、网络化、协作型一体化的教育、科研、办理和生活服务的新式办理模式。那么一般的智慧校园信息渠道主要有哪些特色呢&#xff1f; 不同品牌的智慧校园信息渠道&…

【html5】03-新表单元素及属性

目录 1 引言 2 智能表单控件-type 3 表单属性 form input 5 答疑--解决required自定义提示信息 1 引言 HTML5引入了一系列新的表单输入类型&#xff0c;如email、url、number、range、date、time、datetime-local、month、week、search、color和tel等。这些新类型增强了表…

tiktok 算法分析

第一步&#xff1a; 先找到关键函数 第二步&#xff1a; 第三步&#xff1a; 初始化码表 第四步&#xff1a; 通过计算更新码表 第五步&#xff1a;

grafana + Prometheus + node-exporter + pushgateway + alertmanager的监控解决方案

业内比较著名的监控解决方案&#xff0c;据笔者所知&#xff0c;大概是三套&#xff1a; 一个是zabbix的解决方案&#xff0c;一个是prometheusgrafana&#xff0c;一个是ELK zabbix比较重&#xff0c;而且原生支持监控SNMP&#xff0c;自带一个仪表盘&#xff0c;不需要额外…

【Crypto】一眼就解密

文章目录 前言一眼就解密解题感悟 前言 Basic写累了&#xff0c;写写别的 一眼就解密 一眼md5试一试 小小flag 拿下&#xff01; 解题感悟 30秒搞定

第十八篇:探索非关系型数据库:从入门到实践

探索非关系型数据库&#xff1a;从入门到实践 1. 引言 1.1 非关系型数据库的崛起&#xff1a;背景与重要性 在过去的几十年里&#xff0c;关系型数据库&#xff08;RDBMS&#xff09;一直在数据存储和管理领域占据主导地位。其严谨的结构化数据模型以及强大的事务处理能力&am…

Lin网络一:DHCP与FTP

目录 1、了解DHCP服务 2、使用DHCP服务有哪些好处 3、DHCP的分配方式 4、DHCP的租约过程 客户机请求IP地址 服务器确定租约 重新登陆 上述总结 配置&#xff1a; 5、传输文件到Linux服务器的常用工具: 1、FTP 文件传输协议 2、FTP传输模式&#xff1a; 3、FTP控制…

力扣第206题-反转链表

反转链表的效果示意图 要改变链表结构时&#xff0c;通常加入一个创建的临时头结点会更容易操作 时间复杂度&#xff1a;遍历2遍&#xff0c;2n 空间复杂度&#xff1a;额外创建一个栈&#xff0c;n (空间创建一个数组长度最大为5000&#xff0c;你说这个数组是栈也可以&…

基于svm的水果识别

1、程序界面介绍 该程序GUI界面包括待检测水果图片加载、检测结果输出、清空可视化框等。其中包括训练模型、加载图片、重置、识别检测按钮。 程序GUI界面 识别玉米识别西瓜 分类器识别水果基本原理&#xff1a; 由于每种水果的外形存在很大差异&#xff0c;比如西瓜与玉米&…

C语言/数据结构——每日一题(设计循环队列)

一.前言 上一次我们分享了关于队列的基本实现——https://blog.csdn.net/yiqingaa/article/details/139033067?spm1001.2014.3001.5502 现在我们将使用队列知识来解决问题——设计循环队列&#xff1a;https://leetcode.cn/problems/design-circular-queue/submissions/533299…

深度神经网络——什么是自动编码器?

自动编码器 自动编码器&#xff08;Autoencoders&#xff09;是无监督学习领域中一种重要的神经网络架构&#xff0c;它们主要用于数据压缩和特征学习。 自动编码器的定义&#xff1a; 自动编码器是一种无监督机器学习算法&#xff0c;它通过反向传播进行训练&#xff0c;目标…

【从C++到Java一周速成】章节10:封装、继承、方法的重写、多态

章节10&#xff1a;封装、继承、方法的重写、多态 【1】封装1.高内聚&#xff0c;低耦合2.代码层面的体现 【2】继承【3】方法的重写【4】多态 【1】封装 1.高内聚&#xff0c;低耦合 高内聚&#xff1a;类的内部数据操作细节自己完成&#xff0c;不允许外部干涉&#xff1b;…

如何使用 CapSolver 扩展找到 Google reCAPTCHA 站点密钥?

网站安全性在当今至关重要&#xff0c;Google reCAPTCHA 作为防止垃圾邮件和滥用行为的前线防御系统起着关键作用。reCAPTCHA 站点密钥是确保网站交互由人类驱动的唯一标识符。了解如何找到这个密钥对于网站管理员和开发人员来说至关重要。 什么是 reCAPTCHA 站点密钥 reCAPT…

智能家居6 -- 配置 ini文件优化设备添加

不知道什么是ini的朋友可以先看这篇:一文带你入门ini格式-CSDN博客 准备 如下图: 在src 下面添加 ini.c 在inc 下面添加 ini.h 在 receive_interface.c 里面包含头文件&#xff0c;把之前添加的设备类注释掉 这时候就可以把相关设备的(.c .h)文件给删掉了 如下图: 修改/添…

CDH6.3.2集成Flink1.17

直接运行脚本即可&#xff0c;一键输出相关依赖包 运行步骤已给到文档 下载地址