【网络】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,一经查实,立即删除!

相关文章

使用崖山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程序不用占用后台…

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…

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;还记得之前我们是通过什么方法分割…

[论文笔记] 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…

layui 让table里的下拉框不被遮挡

记录&#xff1a;layui 让table里的下拉框不被遮挡 /* 这个是让table里的下拉框不被遮挡 */ .goods_table .layui-select-title,.goods_table .layui-select-title input{line-height: 28px;height: 28px; }.goods_table .layui-table-cell {overflow: visible !important; }.…

【Django】网上蛋糕项目商城-注册,登录,修改用户信息,退出功能

概念 通过以上多篇文章的讲解&#xff0c;对该项目的功能已经实现了很多&#xff0c;本文将对该项目的用户注册&#xff0c;登录&#xff0c;修改用户信息&#xff0c;以及退出等功能的实现。 注册功能实现 点击head.html头部页面的注册按钮&#xff0c;触发超链接跳转至use…

操作系统发展简史(Unix/Linux 篇 + DOS/Windows 篇)+ Mac 与 Microsoft 之风云争霸

操作系统发展简史&#xff08;Unix/Linux 篇&#xff09; 说到操作系统&#xff0c;大家都不会陌生。我们天天都在接触操作系统 —— 用台式机或笔记本电脑&#xff0c;使用的是 windows 和 macOS 系统&#xff1b;用手机、平板电脑&#xff0c;则是 android&#xff08;安卓&…

来聊聊去中心化Redis集群节点如何完成通信

写在文章开头 今天我们来聊点有意思的&#xff0c;关于redis中集群间通信的设计与实现&#xff0c;本文将从源码的角度分析redis集群节点如何利用Gossip协议完成节点间的通信与传播&#xff0c;希望对你有帮助。 Hi&#xff0c;我是 sharkChili &#xff0c;是个不断在硬核技术…

MAVSKD-Java开源库mavsdk_server库macOS平台编译

1.下载源码 2.使用IDEA打开,进行mavsdk_server目录,使用gradle进行编译 3.开始编译时会自动下载依赖 4.下载完成后,会自动编译 5.编译成功 6.成功生成AAR文件

2024算力基础设施安全架构设计与思考(免费下载)

算网安全体系是将数据中心集群、算力枢纽、一体化大数据中心三个层级的安全需求进行工程化解耦&#xff0c;从国家安全角度统筹设计&#xff0c;通过安全 服务化方式&#xff0c;依托威胁情报和指挥协同通道将三层四级安全体系串联贯通&#xff0c;达成一体化大数据安全目标。 …

文件IO(Ubuntu)

文件IO 目的 将数据写入文件中 与标准IO的区别 &#xff08;为什么要学习文件IO&#xff09; 标准IO只能操作普通文件和特殊的管道文件 文件IO能操作几乎所有的的文件 缓存区的目的 标准IO有缓存区 文件IO没有缓存区 根据右图描述 标准IO 文件IO buffer缓存区 有缓存区…