【网络】Socket编程

文章目录

  • 正确理解端口号
    • 理解源IP地址和目的IP地址
    • 认识端口号
    • 端口号和进程ID
  • 理解Socket
    • 网络字节序
    • socket编程接口
      • 创建socket套接字
      • bind绑定套接字
      • listen建立监听
      • accept接受连接
      • connect建立连接
      • sendto发送数据
      • 接收数据
      • close关闭套接字
    • sockaddr结构体

正确理解端口号

理解源IP地址和目的IP地址

我们知道通过IP地址我们能在网络中唯一标识一台主机,这也就意味着,只要我知道你的IP地址,就能向你的主机发送数据。但是这有一个问题,主机接收到数据之后发送给哪个进程呢?也就是说,光靠IP地址我们只能找到目标主机,但是更为详细的选择哪个进程就无能为力了。所以我们需要有端口号。端口号就是主机唯一标识进程的一个16字节整数,拿着IP地址和端口号,我们就能在浩瀚的网络中找到目标主机的目标进程。更为准确的,网络通信本质还是进程间通信,只不过这两个进程可能不在一台主机上。
在这里插入图片描述

认识端口号

根据上面介绍,总结端口号的特点:

  • 端口号是一个2字节16位的整数
  • 端口号用来标识一个进程,告诉操作系统,当前从网卡收到的数据要交给哪一个进程
  • IP地址+端口号能在网络世界中标识唯一一个进程
  • 同一台主机下,一个端口号只能被一个进程占用

更为具体地:端口号地范围是0-65535,其中

  • 0-1023表示的是知名端口号,一般是系统或者是特权进程使用
  • 1024-65535:操作系统动态分配的端口号,客户端程序的端口号就是由操作系统从这个范围分配的

端口号和进程ID

我们说到端口号是为了唯一标识一台主机的某个进程,但是为什么不直接使用进程PID呢?进程PID的作用也是标识唯一一个进程呐。原因如下:

  • PID标识的是正在运行中的进程,一旦程序退出,这个进程就找不到了
  • PID是变化的,可能每次运行程序得到的PID都不一样
  • 更深层面上来说,进程ID属于操作系统层面,端口号处于网络层面,如果端口号和进程PID绑定,会让系统进程管理和网络强耦合,实际设计的时候,并没有选择这么做。

理解Socket

综上所述,网络中的两个进程要想相互通信,通信的数据得明确四个属性:源主机的IP+Port,目标主机的IP+Port。我们把IP+Port的组合就称为套接字Socket

网络字节序

我们知道,数据在内存中的存储方式有大小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大小端之分,网络数据流也有大小端之分。如果传输数据双方的主机一个是大端存储,一个是小端存储,假设我们不做任何处理就将数据发送能够给对方,那对方拿到的数据就会出现乱码。为了避免这种情况,我们需要在将数据发送到网络之前将数据转换成网络字节序,具体的:
TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址高字节,所以如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可。

此外,我们可以在代码中调用相关库函数来做网络字节序和主机字节序的转换:
在这里插入图片描述
其中

  • htonl函数的作用是将 32 位的长整数从主机字节序转换为网络字节序,例如将 IP 地址转换后准备发送
  • htons函数的作用是将 16 位的短整数从主机字节序转换为网络字节序,例如将 端口号 地址转换后准备发送
  • ntohl函数的作用是将 32 位的长整数从网络字节序转换为主机字节序,例如将 接收到的 IP 地址转换后使用
  • ntohs函数的作用是将 16 位的短整数从网络字节序转换为主机字节序,例如将接收到的端口号转换后使用

注意以上函数区别。

socket编程接口

下面介绍一些常见的socket接口:

C
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
// 开始监听 socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

一般来说,使用socket编程通常需要包含四个头文件

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

创建socket套接字

可以使用socket函数来创建一个套接字

#include <sys/types.h>
#include <sys/socket.h>// 创建一个IPv4的TCP套接字
int socket(int domain, int type, int protocol);
  • domain:地址簇,常见的有AF_INET(IPv4),和AF_INET6(IPv6)
  • type:套接字类型,常见的有SOCK_STREAM(TCP),SOCK_DGRAM(UDP)
  • protocol:协议,通常为0(自动选择),也可以指定协议,如IPPROTO_TCP IPPROTO_UDP
  • 成功时返回一个套接字描述符,失败时返回-1,并设置error

注意这里的套接字描述符其实就是文件描述符,查看man手册我们可以看到:
在这里插入图片描述
也就是说,调用socket这个函数得到一个文件描述符,在操作系统的内核中,它对应于一个数据结构,存储了该套接字的各种状态信息和资源,例如IP地址、端口号、通信协议、缓冲区等。

bind绑定套接字

bind函数将套接字绑定到一个IP地址和端口号。

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:套接字描述符
  • addr:指向ockaddr结构体的指针,该结构体对象包含了要绑定的地址信息,对于IPv4,使用sockaddr_in 结构体;对于IPv6,使用 sockaddr_in6 结构体。
  • addr_lenaddr指向结构体对象的大小,通常使用sizeof获取
  • 成功时返回0,失败时返回-1并设置errno

listen建立监听

listen函数使套接字进入监听状态,准备接受连接请求。

#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
  • sockfd:套接字描述符
  • backlog:挂起连接的最大队列长度,即最多有多少个连接可以等待被接受
  • 成功时返回0,失败时返回-1并设置errno

accept接受连接

accept函数接受一个连接请求,返回一个新的套接字描述符,用于与客户端通信

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockfd:监听套接字描述符,即listen获取的套接字描述符
  • addr指向sockaddr 结构体对象的指针,用于存储客户端地址信息
  • addrlen:指向addr指向结构体对象的大小
  • 成功时返回新的套接字描述符,失败时返回-1并设置errno

connect建立连接

connect函数用于客户端连接到服务器

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:套接字描述符
  • addr指向sockaddr 结构体对象的指针,用于存储服务器地址信息
  • addrlen: sockaddr 结构体的大小。
  • 成功时返回0,失败时返回-1并设置errno

sendto发送数据

sendto函数是用于在 无连接套接字**(如UDP)上发送数据 的。它允许程序指定目标地址,从而可以在一个套接字上与多个目标进行通信。

#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: 套接字描述符,通过 socket 函数创建
  • buf: 指向要发送的数据缓冲区
  • len: 要发送的数据的长度
  • flags: 发送标志,通常为0
  • dest_add: 指向 sockaddr 结构体的指针,包含目标地址和端口号
  • addrlen: sockaddr 结构体的大小
  • 成功时返回发送的字节数,失败时返回-1,并设置 errno 以指示错误

接收数据

recvfrom 函数用于在无连接的套接字(如UDP)上接收数据,它允许程序获取发送数据的源地址。它常用于UDP服务器接收数据包,并且能够知道数据包的来源

#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: 套接字描述符,通过 socket 函数创建。
  • buf: 指向存储接收数据的缓冲区。
  • len: 缓冲区的长度,即可以接收的最大字节数。
  • flags: 接收标志,通常为0。
  • src_addr: 指向 sockaddr 结构体的指针,用于存储发送方的地址信息。
  • addrlen: 指向 socklen_t 变量的指针,表示 sockaddr 结构体的大小。调用函数时需要设置为 sockaddr 结构体的大小,函数返回时设置为实际地址的长度。

close关闭套接字

跟关闭文件描述符一样,创建的套接字描述符用完之后也需要手动关闭,同样的使用close函数。

#include<unistd.h>
int close(int fd);
  • 成功返回0,失败返回-1

sockaddr结构体

sockaddr 结构体用于存储套接字地址信息。该结构体是网络地址结构体的通用形式。在具体使用时,通常会用到特定协议族的派生结构体,如 sockaddr_in、sockaddr_un。各种网络协议的地址格式并不相同.
在这里插入图片描述

  • sockaddr:
struct sockaddr {sa_family_t sa_family;  // 地址族(Address family)char sa_data[14];       // 套接字地址数据(Socket address data)
};
  • sockaddr_in:
struct sockaddr_in {sa_family_t sin_family;   // 地址族(AF_INET)in_port_t sin_port;       // 端口号(Port number),网络字节序struct in_addr sin_addr;  // IPv4地址char sin_zero[8];         // 填充字节,使结构体大小与 `sockaddr` 一致
};
  • in_addr:
struct in_addr {uint32_t s_addr;  // 32位IPv4地址,网络字节序
};

in_addr 用来表示一个 IPv4 的 IP 地址. 其实就是一个 32 位的整数;

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

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

相关文章

分布式唯一id的7种方案

背景 为什么需要使用分布式唯一id&#xff1f; 如果我们的系统是单体的&#xff0c;数据库是单库&#xff0c;那无所谓&#xff0c;怎么搞都行。 但是如果系统是多系统&#xff0c;如果id是和业务相关&#xff0c;由各个系统生成的情况下&#xff0c;那每个主机生成的主键id就…

Linux网络 -- TCP FIN包发送超时时间设置

使用 SO_LINGER 选项控制FIN包发送的超时时间 技术背景 在TCP连接中&#xff0c;当应用程序调用 close 或 shutdown 函数关闭一个socket时&#xff0c;操作系统内核会发送一个FIN包以通知对端连接即将关闭。默认情况下&#xff0c;内核会等待所有未发送的数据发送完毕后再发送…

使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试

前言 首届YashanDB「迁移体验官」开放后&#xff0c;陆续收到「体验官」们的投稿&#xff0c;小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试》&#xff08;作者&#xff1a;尚雷&#xff09;&#xff0c…

PHP宠物店萌宠小程序系统源码

&#x1f43e;萌宠生活新方式&#x1f43e; &#x1f3e1;【一键直达萌宠世界】 你是否也梦想着拥有一家随时能“云撸猫”、“云吸狗”的神奇小店&#xff1f;现在&#xff0c;“宠物店萌宠小程序”就是你的秘密花园&#xff01;&#x1f31f;只需轻轻一点&#xff0c;就能瞬…

什么是股指期货交割?股指期货交割的例子

股指期货交割是指在股指期货合约到期时&#xff0c;投资者需要按照合约规定完成的结算过程。与一般的商品期货、国债期货或外汇期货不同&#xff0c;股指期货采用的是现金交割方式。 股指期货交割的方式 【现金交割】股指期货的交割不需要实际交割一篮子股票指数成分股。相反…

(社恐福音)用python写一个定时弹窗功能

背景 背景是换了一个工作&#xff0c;需要点外卖了 写代码太认真的时候又经常忘记 这时候就需要一个闹钟 手机闹钟声音太大 会影响他人 所以用python 写一个弹窗功能&#xff0c;只影响自己 效果图 原理 管理列表和定时功能通过windows自带的计划完成 python程序不用占用后台…

js中! 、!!、?.、??、??=的用法及使用场景

js中! 、 !. 、!、?.、.?、??、??的用法及使用场景 !!!?.??????、?? 区别 !. &#xff08;ts&#xff09;注意 ! (非空断言符号) 用于取反一个布尔值或将一个值转换为布尔类型并取反 const a true; const b false; const value !a; // false const value !…

https和http区别

1、安全性 HTTP信息是明文传输&#xff0c;而HTTPS则通过SSL/TLS协议进行加密传输&#xff0c;确保数据传输的安全性。HTTPS可以验证服务器身份&#xff0c;防止中间人攻击&#xff0c;保护数据的完整性和保密性。 2、端口号 HTTP默认使用80端口&#xff0c;而HTTPS默认使用…

最佳实践:设计思维:“6+1”迭代过程的创新实践丨IDCF

谢志萌 研发效能&#xff08;DevOps&#xff09;工程师&#xff08;中级&#xff09;认证学员 一、前言 “有效的Devops关键在于专注于人员和文化&#xff0c;而不仅仅是工具和技术。” -John Willis 随着数字化转型的加速&#xff0c;组织越来越依赖于快速、高效的软件交…

7月18日学习打卡,数据结构堆

hello大家好呀&#xff0c;本博客目的在于记录暑假学习打卡&#xff0c;后续会整理成一个专栏&#xff0c;主要打算在暑假学习完数据结构&#xff0c;因此会发一些相关的数据结构实现的博客和一些刷的题&#xff0c;个人学习使用&#xff0c;也希望大家多多支持&#xff0c;有不…

ARM架构(二)—— arm v7/v8/v9寄存器介绍

1、ARM v7寄存器 1.1 通用寄存器 V7 V8开始 FIQ个IRQ优先级一样&#xff0c; 通用寄存器&#xff1a;31个 1.2 程序状态寄存器 CPSR是程序状态毒存器&#xff0c;保存条件标志位&#xff0c;中断禁止位&#xff0c;当前处理器模式等控制和状态位。每种异常模式下还存在SPSR&…

《系统架构设计师教程(第2版)》第12章-信息系统架构设计理论与实践-02-信息系统架构

文章目录 1. 概述1.1 信息系统架构&#xff08;ISA&#xff09;1.2 架构风格 2. 信息系统架构分类2.1 信息系统物理结构2.1.1 集中式结构2.1.2 分布式结构 2.2 信息系统的逻辑结构1&#xff09;横向综合2&#xff09;纵向综合3&#xff09;纵横综合 3. 信息系统架构的一般原理4…

Pandas教程:近万字讲解在Pandas中如何操作Excel

目录 1. 安装与配置 2. 读取Excel文件 2.1 基本用法 2.2 指定工作表 2.3 指定单元格范围 3. 数据检查与预处理 3.1 查看数据的基本信息 3.2 数据类型检查与转换 3.3 检查缺失值 3.4 处理缺失值 4. 数据清洗与转换 4.1 重命名列 4.2 删除重复数据 4.3 数据替换 4…

Android使用ANativeWindow更新surfaceView内容最简Demo

SurfaceView简介 SurfaceView对比View的区别 安卓的普通VIew,都依赖于当前Activity的Window的surface&#xff0c;这个surface用于承载view树从底到顶绘制出来的所有内容&#xff0c;因此任何一个view需要更新时&#xff0c;都需要把所有view中底到顶进行更新&#xff0c;即使使…

解决:Linux上SVN 1.12版本以上无法直接存储明文密码

问题&#xff1a;今天在Linux机器上安装了SVN&#xff0c;作为客户端使用&#xff0c;首次执行SVN相关操作&#xff0c;输入账号密码信息后&#xff0c;后面再执行SVN相关操作&#xff08;比如"svn update"&#xff09;还是每次都需要输入密码。 回想以前在首次输入…

Python进阶(4)--正则表达式

正则表达式 在Python中&#xff0c;正则表达式&#xff08;Regular Expression&#xff0c;简称Regex&#xff09;是一种强大的文本处理工具&#xff0c;它允许你使用一种特殊的语法来匹配、查找、替换字符串中的文本。 在这之前&#xff0c;还记得之前我们是通过什么方法分割…

实习问题总结

为什么使用GRPC作为通信方式&#xff0c;对比如REST好处在哪里&#xff1f; 使用protobuf作为序列化格式&#xff0c;以二进制进行传输&#xff0c;减小了数据包的大小&#xff0c;效率高 proto强类型定义、支持复杂数据类型&#xff0c;编译运行可以进行严格的数据验证&#…

[论文笔记] pai-megatron-patch Qwen2-CT 长文本rope改yarn

更改: # Copyright (c) 2024 Alibaba PAI and Nvidia Megatron-LM Team. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License a…

【系统架构设计】数据库系统(二)

数据库系统&#xff08;二&#xff09; 数据库模式与范式数据库设计数据库设计的方法数据库设计的基本步骤 事务管理并发控制故障和恢复 备份与恢复分布式数据库系统数据仓库数据挖掘NoSQL大数据 数据库模式与范式 数据库设计 数据库设计的方法 目前已有的数据库设计方法可分…

element UI :el-table横向列内容超出宽度,滚动条不显示问题

是否能解决你问题的前提 **看到这篇文章的解决问题的方案之前&#xff0c;请先回忆你是否在项目中的全局样式或者私有组件中去单独设置过滚动条样式。如果有 请继续往下看&#xff1a;**单独设置过滚动条样式代码实例&#xff1a; ::-webkit-scrollbar {/*滚动条整体样式*/wi…