第56章:socket介绍

news2025/2/24 22:13:16

socket允许位于同一主机(计算机)或使用网络连接起来的不同主机上的应用程序之间交换数据

概述

在一个典型的客户端/服务器场景中,应用程序使用socket 进行通信的方式如下:

  • 各个应用程序创建一个socket。socket 是一个允许通信的“设备”,两个应用程序都需要用到它。
  • 服务器将自己的socket 绑定到一个众所周知的地址(名称)上使得客户端能够定位到它的位置。
    使用 socket()系统调用能够创建一个socket,它返回一个用来在后续系统调用中引用该socket 的文件描述符。
fd = socket(domain, type, protocol);

在本书介绍的所有应用程序中,protocol 参数总是被指定为0。

通信domain

通信domain可以确定:

  • 识别出一个 socket 的方法(即socket“地址”的格式);
  • 通信范围(即是在位于同一主机上的应用程序之间还是在位于使用一个网络连接起来的不同主机上的应用程序之间)。

现代操作系统支持的domain如下表:

Domain执行的通信应用程序间的通信地址格式地址结构
AF_UNIX内核中同一主机路径名sockaddr_un
AF_INET通过IPv4通过 IPv4 网络连接起来的主机32 位IPv4 地址+16 位端口号sockaddr_in
AF_INET6通过IPv6通过 IPv6 网络连接起来的主机128 位IPv4 地址+16 位端口号sockaddr_in6

socket类型

有流(SOCK_STREAM)和数据报(SOCK_DGRAM)两种类型,在UNIX和Internet domain中都得到支持,属性总结如下表:

属性数据报
可靠地递送?
消息边界保留?
面向连接?

流 socket(SOCK_STREAM)提供了一个可靠的双向的字节流通信信道,一个流socket 只能与一个对等socket 进行连接。

在 Internet domain 中,数据报socket 使用了用户数据报协议(UDP),而流socket 则(通常)使用了传输控制协议(TCP)。

socket系统调用

关键的调用包括以下几种:

  • socket()系统调用创建一个新socket。
  • bind()系统调用将一个socket 绑定到一个地址上。通常,服务器需要使用这个调用来将其socket 绑定到一个众所周知的地址上使得客户端能够定位到该socket 上。
  • listen()系统调用允许一个流socket 接受来自其他socket 的接入连接。
  • accept()系统调用在一个监听流socket 上接受来自一个对等应用程序的连接,并可选地返回对等socket 的地址。
  • connect()系统调用建立与另一个socket 之间的连接。

socket I/O 可以使用传统的read()和write()系统调用或使用一组socket 特有的系统调用(如send()、recv()、sendto()以及recvfrom())来完成。

在 Linux 上可以通过调用ioctl(fd, FIONREAD, &cnt)来获取文件描述符fd 引用的流
socket 中可用的未读字节数。对于数据报socket 来讲,这个操作会返回下一个未读数据报中的字节数(如果下一个数据报的长度为零的话就返回零)或在没有未决数据报的情况下返回0.

创建一个socket: socket()

#include <sys/socket.h>
int socket(int domain, int type, int protocol)
// Returns file descriptor on success, or -1 on error

将socket 绑定到地址:bind()

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
// Returns 0 on success, or -1 on error
  • addr 参数是一个指针,它指向了一个指定该socket 绑定到的地址的结构。传入这个参数的结构的类型取决于socket domain。
  • addrlen 参数指定了地址结构的大小。addrlen 参数使用的socklen_t 数据类型在SUSv3 被规定为一个整数类型。

通用socket 地址结构:struct sockaddr

每种socket domain 都使用了不同的地址格式,但是诸如bind()之类的系统调用适用于所有socket domain,因此它们必须要能够接受任意类型的地址结构。

为支持这种行为,socket API 定义了一个通用的地址结构struct sockaddr。

这个类型的唯一用途是将各种domain 特定的地址结构转换成单个类型以供socket 系统调用中的各个参数使用。

struct sockaddr
{
	sa_family_t_sa_family; // addr family
	char sa_data[14]; // sock addr (size varies according to socket domain)
};

流socket

流socket系统调用流程如下图:
流socket系统调用

监听接入连接:listen()

#include <sys/socket.h>
int listen(int sockfd, int backlog);
// Returns 0 on success, or -1 on error

无法在一个已连接的socket(即已经成功执行connect()的socket 或由accept()调用返回的socket)上执行listen()。

客户端可能会在服务器调用accept()之前调用connect()。这种情况是有可能会发生的,如服务器可能正忙于处理其他客户端。这将会产生一个未决的连接。内核必须要记录所有未决的连接请求的相关信息,这样后续的accept()就能够处理这些请求了。

backlog 参数允许限制这种未决连接的数量。在这个限制之内的连接请求会立即成功。之外的连接请求就会阻塞直到一个未决的连接被接受(通过accept()),并从未决连接队列删除为止。

SUSv3 规定实现应该通过在<sys/socket.h>中定义SOMAXCONN常量来发布这个限制。在Linux 上,这个常量的值被定义成了128。但从内核2.4.25 起,Linux允许在运行时通过Linux 特有的/proc/sys/net/core/somaxconn 文件来调整这个限制。

接受连接: accept()

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socktlen_t *addrlen);
// Returns file descriptor on success, or -1 on error

理解 accept()的关键点是它会创建一个新socket,并且正是这个新socket 会与执行connect()的对等socket 进行连接。accept()调用返回的函数结果是已连接的socket 的文件描述符。监听socket(sockfd)会保持打开状态,并且可以被用来接受后续的连接.

连接到对等socket:connect()

#include <sys/socket.h>
int connect(int fd, const struct sockaddr *addr, socklen_t addrlen);
// Returns 0 on success, or -1 on error

流socket I/O

要执行 I/O 需要使用read()和write()系统调用(或在61.3 节中描述的socket 特有的send()和recv()调用)。由于socket 是双向的,因此在连接的两端都可以使用这两个调用。

一个 socket 可以使用close()系统调用来关闭或在应用程序终止之后关闭。

连接终止:close()

终止一个流socket 连接的常见方式是调用close()。如果多个文件描述符引用了同一个socket,那么当所有描述符被关闭之后连接就会终止。

数据报socket

交换数据报:recvfrom 和sendto()

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
// Returns number of bytes sent, or -1 on error

不管 length 的参数值是什么,recvfrom()只会从一个数据报socket 中读取一条消息。如果消息的大小超过了length 字节,那么消息会被静默地截断为length 字节。

在数据报socket 上使用connect()

尽管数据报socket 是无连接的,但在数据报socket 上应用connect()系统调用仍然是起作用的。在数据报socket 上调用connect()会导致内核记录这个socket 的对等socket 的地址。

当一个数据报 socket 已连接之后:

  • 数据报的发送可在socket 上使用write()(或send())来完成并且会自动被发送到同样的对等socket 上。与sendto()一样,每个write()调用会发送一个独立的数据报;
  • 在这个 socket 上只能读取由对等socket 发送的数据报。

注意 connect()的作用对数据报socket 是不对称的。上面的论断只适用于调用了connect()数据报socket,并不适用于它连接的远程socket(除非对等应用程序在其socket 上也调用了connect())

为一个数据报socket 设置一个对等socket的优势:在该socket 上传输数据时可以使用更简单的I/O 系统调用,无需使用指定了dest_addr 和addrlen 参数的sendto(),而只需要使用write()即可

对等socket的应用场景: 主要对那些需要向单个对等socket(通常是某种数据报客户端)发送多个数据报的应用程序是比较有用的。

总结

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

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

相关文章

项目压测相关

几个重要指标的关系 QPS 并发数/平均响应时间 并发数 QPS*平均响应时间 也就是说&#xff0c;并发连接数代表服务器抗压能力&#xff0c;接收连接的能力。qps代表在相同的并发数下&#xff0c;服务器处理的速度&#xff0c;响应时间越短&#xff0c;那么qps就越大。 不是说并发…

Unity Lightmapping Setting

如下图&#xff1a; Lightmapper: 使用什么硬件或算法渲染 Progressive CPU、Progressive GPU、Enlighten(新的算放目前用的比较少) 此数值会被用于分别乘以Direct Samples&#xff0c;Indirect Samples和Environment Samples这三个数值。这三个数值会被应用于…

【Netty】Netty 如何实现零拷贝(八)

文章目录 前言一、Java 实现零拷贝1.1 Java提供 mmap/write 方式1.2 Java 提供 sendfile 方式 二、Netty 实现零拷贝2.1 CompositeByteBuf 方式2.1 wrap 方式2.3 slice 方式2.4 FileRegion 方式 总结 前言 回顾Netty系列文章&#xff1a; Netty 概述&#xff08;一&#xff0…

李沐多模态串讲笔记

李沐多模态串讲笔记 0.来源1.回顾1.1 ViLT回顾1.2 Clip回顾1.3回顾小结 2.ALBEF2.1摘要2.2主体方法部分2.2.1模型设计2.2.2目标函数2.2.3momentum distillation 动量蒸馏 2.3下游任务和实验结果 3.VLMo3.1论文贡献3.2研究动机3.3主体方法部分3.3.1模型设计3.3.2分阶段的训练策略…

Android 12 通知样式整理

目录 0. &#x1f4c2; 前言 1. &#x1f531; 通知样式总览 2. ⚛️ 通知样式详解 2.1 Simple Notifiaction 2.2 Action Notifiaction 2.3 Remote Input Notifiaction 2.4 Big Picture Notifiaction 2.5 Big Text Notifiaction 2.6 Inbox Notifiaction 2.7 Media No…

Cobalt Strike工具基本使用

Cobalt Strike 安装启动启动server端启动client目标机器连接 工具基使用用户驱动攻击屏幕截图进程列表键盘记录文件管理远程vnc远程代理端口扫描 生成后门被攻击者运行后门文件后查看结果 钓鱼攻击信息收集网站克隆文件下载 安装 网盘地址&#xff1a;链接&#xff1a;https:/…

AntDB-S流式数据库体验

本文作者&#xff1a;彭冲老师&#xff0c;上一篇彭老师体验了亚信刚发布的社区版AntDB-T数据库&#xff0c;文章如下&#xff1a; AntDB-T交易型数据库体验 本文继续体验AntDB-S流式数据库的&#xff0c;AntDB-S目前还未开放社区版&#xff0c;可以联系AntDB小助手进行体验。…

电压放大器的主要指标有哪些方面

电压放大器是电子电路中常用的器件&#xff0c;在选择和评估电压放大器时&#xff0c;需要考虑以下几个主要指标&#xff1a; 输入电阻&#xff08;Input Resistor&#xff09;&#xff1a;输入电阻是指放大器输入端的电阻值&#xff0c;它反映了放大器将输入信号转换成输出信号…

亚马逊,速卖通,国际站卖家在做测评时如何将风险降到最低呢?

测评是亚马逊卖家提升产品可信度和销售表现的重要手段 现在的测评市场遭到卖家们的极力吐槽&#xff0c;想要找到靠谱的资源也越来越难。据了解&#xff0c;去年很多骗子&#xff0c;中介都涌进测评市场&#xff0c;随意报价&#xff0c;导致整个市场鱼龙混杂&#xff0c;卖家…

MyBatis源码学习四之二级缓存

MyBatis源码学习四之二级缓存 MyBatis的缓存使用的也比较多&#xff0c;而缓存的都实现了一个父类的接口Cache。 一、加载缓存类PerputualCache public static void main(String[] args) {InputStream inputStream null;try {inputStream Resources.getResourceAsStream(&q…

NRK3303语音识别芯片在照明灯上的运用,一款可分布式语音IC方案

随着科技的不断进步&#xff0c;人们对于家居生活中的照明设备的要求也逐渐提高。传统的照明方式已经不能满足人们对智能家居的需求&#xff0c;我们需要更加智能、易于操作、高效节能的智能化照明系统。因此&#xff0c;智能照明应运而生&#xff0c;为我们提供了更加智能化、…

倍福触摸屏维修控制面板CP6606-0001-0020

适合控制柜安装的CP6600和CP6606面板型PC&#xff0c;适用于机械制造和设备工程等各种应用&#xff1b;可以安装TwinCAT自动化软件和 Windows Embedded操作系统&#xff0c;用作单独的控制器&#xff0c;也可以用作远程桌面显示器。 倍福触摸屏常见故障分类&#xff1a; 1、磨…

linux学习[11]磁盘与文件系统(2):lsblkblkidpartedfdiskgdiskmkfs

文章目录 前言&#xff1a;1. 磁盘容量1.1 lsblk1.2 blkid1.3 parted 2. 磁盘分区2.1 fdisk/gdisk2.2 磁盘分区实例参考&#xff1a; 3. 磁盘格式化3.1 mkfs.xfs3.2 mkfs.ext43.3 mkfs.vfat 总结&#xff1a; 前言&#xff1a; 写了VMware的磁盘扩容之后&#xff0c;磁盘分区格…

深度学习基础-卷积神经网络CNN+深度学习(无代码仅理解)

参考书籍&#xff1a;&#xff08;找不到资源可以后台私信我&#xff09; 《深度学习入门&#xff1a;基于Python的理论与实现 (斋藤康毅)》 CNN 概括 其中pooling层有时候会被省略&#xff0c;卷积层的输入输出图像称为特征图&#xff08;feature map&#xff09;&#xff0c…

多线程-Thread类的常用方法和生命周期

Thread类的常用结构 构造器 public Thread():分配一个新的线程对象。public Thread(String name):分配一个指定名字的新的线程对象。public Thread(Runnable target):指定创建线程的目标对象&#xff0c;它实现了Runnable接口中的run()方法。public Thread(Runnable target,S…

Python实现温度植被干旱指数(TVDI)的计算

前言 温度植被干旱指数&#xff08;Temperature Vegetation Dryness Index&#xff0c;TVDI&#xff09;是一种基于光学与热红外遥感通道数据进行植被覆盖区域表层土壤水分反演的方法。作为同时与归一化植被指数(NDVI)和地表温度(LST)相关的温度植被干旱指数(TVDI)可用于干旱监…

第二十五节:通信之WLAN(WiFi聚合)

欢迎大家一起学习探讨通信之WLAN。为了减少帧交互中额外资源占用开销&#xff0c;提高WiFi网络系统整体运行效率&#xff0c;802.11n协议引入定义了聚合功能。本节将基于协议定义内容和实例&#xff0c;详细分析“A-MSDU"和“A-MPDU”两种聚合功能。 关键字 S1G(Sub 1 GH…

linux0.12-10-6-tty_io.c

[539页] 10-6 tty_io.c程序 10-6-1 功能描述 每个tty设备有3个缓冲队列&#xff0c;分别是读缓冲队列(read_q)、写缓冲队列(write_q)和辅助缓冲队列(secondary)&#xff0c;定义在tty_struct结构中(include/linux/tty.h)。 对于每个缓冲队列&#xff0c;读操作是从缓冲队列的…

数据可视化:部分整体类可视化图表大全

图表是处理数据的重要组成部分&#xff0c;因为它们是一种将大量数据压缩为易于理解的格式的方法。数据可视化可以让受众快速Get到重点。 数据可视化的图表类型极其丰富多样&#xff0c;而且每种都有不同的用例&#xff0c;通常&#xff0c;创建数据可视化最困难的部分是确定哪…