【网络】Socket编程

news2024/9/21 18:47:50

文章目录

  • 正确理解端口号
    • 理解源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.coloradmin.cn/o/1935674.html

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

相关文章

Windows 电脑部署 ollama3 并安装模型

Windows 电脑部署 ollama3 并安装模型 部署中为了尽可能减少对本地环境的污染&#xff0c;使用 Docker 安装&#xff01; github: https://github.com/ollama/ollama 准备部署文件 version: 3.8services:ollama:volumes:- ./models:/root/.ollama # 将本地文件夹挂载到容器中…

独立游戏《星尘异变》UE5 C++程序开发日志7——实现加载界面

目录 一、创建自定义AssetManager类 二、异步加载资产 三、加载界面UI的实现 1.UI布局 2.在打开关卡前和进入关卡后创建UI并统计进度 有时可能会遇到关卡已经进去但依然会卡顿一段时间的情况&#xff0c;所以我们需要在进入关卡后&#xff0c;玩家可以操作关卡之前&#x…

RAG技术进化史:从初级到高级,再到模块化RAG架构的创新发展

大型语言模型&#xff08;LLMs&#xff09;通过在自然语言任务及其它领域的成功应用&#xff0c;如 ChatGPT、Bard、Claude 等所示&#xff0c;已经彻底改变了 AI 领域。这些 LLMs 能够生成从创意写作到复杂代码的文本。然而&#xff0c;LLMs 面临着幻觉、过时知识和不透明、无…

Codeforces Round 672 (Div. 2) C1. Pokémon Army (easy version) (DP)

不知道能不能用贪心&#xff0c;反正我是没看出来&#xff0c;所以用DP求解。 首先分析一下题意&#xff0c;我们要在一段序列中取出一段子序列&#xff0c;然后让这段子序列按顺序逐个先加后减最终得到的结果最大。 如果要用DP&#xff0c;那么我们首先就要思考怎么表示状态…

心好累,早点睡!永远不要提前焦虑——早读(逆天打工人爬取热门微信文章解读)

你们遇到心烦的事&#xff0c;会怎么排解呢&#xff1f; 引言Python 代码第一篇 洞见 永远不要提前焦虑第二篇 故事来源于生活结尾 引言 这两天天气都是阴雨 雨时而大 时而小 就是下个不停 老天还算给面子 上班路上总是细雨或者无雨 昨天晚上回来 山地车的前轮有些送动 马上发…

C++从入门到起飞之——this指针 全方位剖析!

个人主页&#xff1a;秋风起&#xff0c;再归来~ C从入门到起飞 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 目录 1、this指针 2、C和C语⾔实现Stack对⽐ C实现Stack代码 C实现Stack代…

深度挖掘行情接口:股票市场中的关键金融数据API接口解析

在股票市场里&#xff0c;存在若干常见的股票行情数据接口&#xff0c;每一种接口皆具备独特的功能与用途。以下为一些常见的金融数据 API 接口&#xff0c;其涵盖了广泛的金融数据内容&#xff0c;其中就包含股票行情数据&#xff1a; 实时行情接口 实时行情接口&#xff1a…

光耦合器技术的实际应用

光耦合器也称为光隔离器&#xff0c;是现代电子产品中的关键组件&#xff0c;可确保电路不同部分之间的信号完整性和隔离。它们使用光来传输电信号&#xff0c;提供电气隔离和抗噪性。 结构和功能 光耦合器通常由以下部分组成&#xff1a; 1.LED&#xff08;发光二极管&#…

Bone Collector-动态规划题解

Bone Collector Problem - 2602 (hdu.edu.cn)https://acm.hdu.edu.cn/showproblem.php?pid2602 Problem Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’…

Ubuntu18 中JDK的安装

文章目录 一、背景说明二、获取安装包三、安装JDK3.1 上传安装包3.2 复制和解压3.3 环境变量的设置3.4 验证安装 四、问题列表4.1 .bashrc文件在哪里&#xff1f;.bashrc是什么&#xff1f;4.2 为什么使用rz上传安装包时会报&#xff1a; 传输失败&#xff1f; 五、总结 一、背…

SpringBoot项目中将word转换为pdf

需求&#xff0c;用户将用户上传的word文件转换成为pdf格式&#xff0c;然后返回 第一步&#xff1a;引入依赖 <dependency><groupId>aspose</groupId><artifactId>aspose-words</artifactId><version>15.8.0-jdk16</version></…

走进标杆 | 宁波市领导一行至金鸡强磁开展专项调研活动

为深入了解supOS助力宁波打造数实融合标杆城市的实践成果&#xff0c;日前&#xff0c;宁波市领导和专家共赴蓝卓supOS标杆项目——宁波金鸡强磁股份有限公司&#xff08;以下简称“金鸡强磁”&#xff09;调研考察&#xff0c;蓝卓总经理助理杨明明、浙江大区副总经理章来胜等…

力扣3202:找出有效子序列的最大长度||

class Solution { public:int maximumLength(vector<int>& nums, int k) {int res0;for(int m0;m<k;m){//假设子序列两数%k之后的结果为m 相当于枚举vector<int> v(k,0);for(auto num:nums){v[num%k]v[(m-num%kk)%k]1; //知道m之后可以知道需要的子序列当前…

做外贸如何高效跟进转化客户

做外贸业务&#xff0c;基本上每天要做的几个事情&#xff0c;开发客户、跟进转化客户、维护客户等等&#xff0c;经常也有外贸新手朋友问我&#xff0c;遇到什么什么客户要怎么跟进&#xff0c;客户不回复怎么办等等&#xff0c;今天就来跟大家聊聊客户跟进转化这块的一些问题…

通俗易懂讲解电池的主要性能参数(下)

接上期内容&#xff0c;上次主要分享影响电池性能评估的两个主要性能参数&#xff1a;电池容量和电池功率。可以点击这里回顾&#xff1a;一起学习电池的主要性能参数和测试方法 今日接着分享电池性能评估的另外两个主要性能参数&#xff1a;电池的使用寿命和自放电率。 上期…

react 快速入门思维导图

在掌握了react中一下的几个步骤和语法&#xff0c;基本上就可以熟练的使用react了。 1、组件的使用。react创建组件主要是类组件和函数式组件&#xff0c;类组件有生命周期&#xff0c;而函数式组件没有。 2、jsx语法。react主要使用jsx语法&#xff0c;需要使用babel和webpa…

SSM 整合(Spring + MyBatis;Spring + Spring MVC)

1. SSM 整合(Spring MyBatis&#xff1b;Spring Spring MVC) 文章目录 1. SSM 整合(Spring MyBatis&#xff1b;Spring Spring MVC)2. 引入相关依赖3. SSM 整合3.1 创建包结构 4. Spring 整合 MyBatis4.1 编写 jdbc.properties4.2 编写 DataSourceConfig 数据源配置4.3 编…

样式布局学习:盒模型浮动FlexboxGrid Layout定位(Positioning响应式布局(Responsive Layout):

看视频确实更容易理解&#xff0c;但是花费时间有点长了&#xff0c;以下是一些官方文档网址&#xff08;可切换中文&#xff09;&#xff0c;也算是节省时间了&#xff1a; 在前端开发中&#xff0c;布局样式是非常重要的一部分&#xff0c;它决定了页面中元素的位置和排列方…

wps office 2019 Pro Plus 集成序列号Vba安装版教程

前言 wps office 2019专业增强版含无云版是一款非常方便的办公软件&#xff0c;我们在日常的工作中总会碰到需要使用WPS的时候&#xff0c;它能为我们提供更好的文档编写帮助我们更好的去阅读PDF等多种格式的文档&#xff0c;使用起来非常的快捷方便。使用某银行专业增强版制作…

snmp++操作之trap

文章目录 snmp六种操作简述Get&#xff08;获取操作&#xff09;&#xff1a;Get Next&#xff08;获取下一个操作&#xff09;&#xff1a;Get Bulk&#xff08;批量获取操作&#xff09;&#xff1a;Set&#xff08;设置操作&#xff09;&#xff1a;Inform&#xff08;通知操…