Linux--Socket编程基础

一、Socket简介

套接字( socket )是 Linux 下的一种进程间通信机制( socket IPC ), 使用 socket IPC 可以使得在不同主机上的应用程序之间进行通信(网络通信),当然也可以是同一台主机上 的不同应用程序。socket IPC 通常使用客户端 <---> 服务器这种模式完成通信,多个客户端可以同时连接到服务器中,与服务器之间完成数据交互。
内核向应用层提供了 socket 接口,对于应用程序开发人员来说,我们只需要调用 socket 接口开发自己的应用程序即可! socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口。 在设计模式中,socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议隐藏在 socket 接口面,对用户来说,一组简单的接口就是全部,让 socket 去组织数据,以符合指定的协议。所以,我们无需深入的去理解 tcp/udp 等各种复杂的 TCP/IP 协议, socket 已经为我们封装好了,我们只需要遵循 socket 的规定去编程,写出的程序自然遵循 tcp/udp 标准的。
当前网络中的主流程序设计都是使用 socket 进行编程的,因为它简单易用,它还是一个标准( BSD socket),能在不同平台很方便移植,比如你的一个应用程序是基于 socket 接口编写的,那么它可以移植到任何实现 BSD socket 标准的平台,譬如 LwIP ,它兼容 BSD Socket ;又譬如 Windows ,它也实现了一套基于socket 的套接字接口,更甚至在国产操作系统中,如 RT-Thread ,它也实现了 BSD socket 标准的 socket 接口。

二、函数接口

1)建立连接前

1、Socket()函数

socket() 函数原型如下所示:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
socket() 函数类似于 open() 函数,它用于创建一个网络通信端点(打开一个网络通信),如果成功则返回 一个网络文件描述符,通常把这个文件描述符称为 socket 描述符( socket descriptor ),这个 socket 描述符跟 文件描述符一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
调用 socket() 与调用 open() 函数很类似,调用成功情况下,均会返回用于文件 I/O 的文件描述符,只不 过对于 socket() 来说,其返回的文件描述符一般称为 socket 描述符。当不再需要该文件描述符时,可调用 close()函数来关闭套接字,释放相应的资源。
如果 socket() 函数调用失败,则会返回 -1 ,并且会设置 errno 变量以指示错误类型。
domain
参数 domain 用于指定一个通信域;这将选择将用于通信的协议族。对于 TCP/IP 协议来说,通常选择 AF_INET 就可以了,也就是选择IPv4协议,当然如果你的 IP 协议的版本支持 IPv6,那么可以选择 AF_INET6。
type
参数 type 指定套接字的类型,当前支持的类型有:
protocol
参数 protocol 通常设置为 0 ,表示为给定的通信域和套接字类型选择默认协议。当对同一域和套接字类型支持多个协议时,可以使用 protocol 参数选择一个特定协议。在 AF_INET 通信域中,套接字类型为 SOCK_STREAM 的默认协议是传输控制协议( Transmission Control Protocol TCP 协议)。在 AF_INET 通信域中,套接字类型为 SOCK_DGRAM 的默认协议时 UDP

2、bind()函数

bind() 函数原型如下所示:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind() 函数用于将一个 IP 地址或端口号与一个套接字进行绑定(将套接字与地址进行关联)。将一个客户端的套接字关联上一个地址没有多少新意,可以让系统选一个默认的地址。一般来讲,会将一个服务器的套接字绑定到一个众所周知的地址--- 即一个固定的与服务器进行通信的客户端应用程序提前就知道的地址 (注意这里说的地址包括 IP 地址和端口号,一般来说,80端口是http服务,22端口是ssh服务)。因为对于客户端来说,它与服务器进行通信,首先需要知道 服务器的 IP 地址以及对应的端口号,所以通常服务器的 IP 地址以及端口号都是众所周知的。
调用 bind() 函数将参数 sockfd 指定的套接字与一个地址 addr 进行绑定,成功返回 0 ,失败情况下返回 -1,并设置 errno 以提示错误原因。
Tips:bind()函数并不是总是需要调用的,只有用户进程想与一个具体的 IP 地址或端口号相关联的时候 才需要调用这个函数。如果用户进程没有这个必要,那么程序可以依赖内核的自动的选址机制来完成自动地址选择,通常在客户端应用程序中会这样做。

3、Listen()函数

listen() 函数只能在服务器进程中使用,让服务器进程进入监听状态,等待客户端的连接请求, listen() 函数在一般在 bind() 函数之后调用,在 accept() 函数之前调用,它的函数原型是:
int listen(int sockfd, int backlog);

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

backlog

参数 backlog 用来描述 sockfd 的等待连接队列能够达到的最大值。在服务器进程正处理客户端连接请求的时候,可能还存在其它的客户端请求建立连接,因为 TCP 连接是一个过程,由于同时尝试连接的用户过多,使得服务器进程无法快速地完成所有的连接请求,那怎么办呢?直接丢掉其他客户端的连接肯定不是一个很好的解决方法。因此内核会在自己的进程空间里维护一个队列,这些连接请求就会被放入一个队列中,服务器进程会按照先来后到的顺序去处理这些连接请求,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限,这个 backlog 参数告诉内核使用这个数值作为队列的上限。而当一个客户端的连接请求到达并且该队列为满时,客户端可能会收到一个表示连接失败的错误,本次请求会被丢弃不作处理。

4、accept()函数

服务器调用 listen() 函数之后,就会进入到监听状态,等待客户端的连接请求,使用 accept() 函数获取客户端的连接请求并建立连接。函数原型如下所示:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

为了能够正常让客户端能正常连接到服务器,服务器必须遵循以下处理流程:

①、调用 socket() 函数打开套接字;
②、调用 bind() 函数将套接字与一个端口号以及 IP 地址进行绑定;
③、调用 listen() 函数让服务器进程进入监听状态,监听客户端的连接请求;
④、调用 accept() 函数处理到来的连接请求。
accept() 函数通常只用于服务器应用程序中,如果调用 accept() 函数时,并没有客户端请求连接(等待连 接队列中也没有等待连接的请求),此时 accept() 会进入阻塞状态,直到有客户端连接请求到达为止。当有 客户端连接请求到达时,accept() 函数与远程客户端之间建立连接, accept() 函数返回一个新的套接字。这个 套接字与 socket() 函数返回的套接字并不同, socket() 函数返回的是服务器的套接字(以服务器为例),而 accept()函数返回的套接字连接到调用 connect() 的客户端,服务器通过该套接字与客户端进行数据交互,譬 如向客户端发送数据、或从客户端接收数据。
所以,理解 accept() 函数的关键点在于它会创建一个新的套接字,其实这个新的套接字就是与执行
connect() (客户端调用 connect() 向服务器发起连接请求)的客户端之间建立了连接,这个套接字代表了服务器与客户端的一个连接。如果 accept() 函数执行出错,将会返回 -1 ,并会设置 errno 以指示错误原因。

5、connect()函数

connect() 函数原型如下所示:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
该函数用于客户端应用程序中,客户端调用 connect()函数将套接字 sockfd 与远程服务器进行连接,参数 addr 指定了待连接的服务器的 IP 地址以及端口号等信息,参数 addrlen 指定了 addr 指向的 struct sockaddr对象的字节大小。
客户端通过 connect() 函数请求与服务器建立连接,对于 TCP 连接来说,调用该函数将发生 TCP 连接的 握手过程,并最终建立一个 TCP 连接,而对于 UDP 协议来说,调用这个函数只是在 sockfd 中记录服务器 IP 地址与端口号,而不发送任何数据。
函数调用成功则返回 0 ,失败返回 -1 ,并设置 errno 以指示错误原因。

2)建立连接后

发送和接收函数
一旦客户端与服务器建立好连接之后,我们就可以通过套接字描述符来收发数据了(对于客户端使用 socket()返回的套接字描述符,而对于服务器来说,需要使用 accept() 返回的套接字描述符),这与我们读写普通文件是差不多的操作,譬如可以调用 read() recv() 函数读取网络数据,调用 write() send() 函数发送数据。

read()函数

read() 函数大家都很熟悉了,通过 read() 函数从一个文件描述符中读取指定字节大小的数据并放入到指 定的缓冲区中,read() 调用成功将返回读取到的字节数,此返回值受文件剩余字节数限制,当返回值小于指定的字节数时并不意味着错误;这可能是因为当前可读取的字节数小于指定的字节数(比如已经接近文件结尾,或者正在从管道或者终端读取数据,或者 read() 函数被信号中断等),出错返回 -1 并设置 errno ,如果在调 read 之前已到达文件末尾,则这次 read 返回 0
套接字描述符也是文件描述符,所以使用 read() 函数读取网络数据时, read() 函数的参数 fd 就是对应的套接字描述符。

recv()函数

recv() 函数原型如下所示:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
不论是客户端还是服务器都可以通过 revc() 函数读取网络数据,它与 read() 函数的功能是相似的。参数sockfd 指定套接字描述符,参数 buf 指向了一个数据接收缓冲区,参数 len 指定了读取数据的字节大小,参数 flags 可以指定一些标志用于控制如何接收数据。

write()函数

通过 write() 函数可以向套接字描述符中写入数据,函数调用成功返回写入的字节数,失败返回 -1 ,并设置 errno 变量。

send()函数

函数原型如下所示:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

send 和 write 很相似,但是 send 可以通过参数 flags 指定一些标志,来改变处理传输数据的方式。

close()函数

当不再需要套接字描述符时,可调用 close() 函数来关闭套接字,释放相应的资源。

3)IP 地址格式转换函数

对于人来说,我们更容易阅读的是点分十进制的 IP 地址,譬如 192.168.1.110 192.168.1.50 ,这其实是一种字符串的形式,但是计算机所需要理解的是二进制形式的 IP 地址,所以我们就需要在点分十进制字符串和二进制地址之间进行转换。

三、总结

1、编写服务器程序

编写服务器应用程序的流程如下:
①、调用 socket() 函数打开套接字,得到套接字描述符;
②、调用 bind() 函数将套接字与 IP 地址、端口号进行绑定;
③、调用 listen() 函数让服务器进程进入监听状态;
④、调用 accept() 函数获取客户端的连接请求并建立连接;
⑤、调用 read/recv write/send 与客户端进行通信;
⑥、调用 close() 关闭套接字。

2、编写客户端程序

①、调用 socket()函数打开套接字,得到套接字描述符;

②、调用 bind()函数将套接字与 IP 地址、端口号进行绑定;

③、调用 connect()连接远端服务器;

④、调用 read/recv、write/send 与客户端进行通信;

⑤、调用 close()关闭套接字。

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

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

相关文章

【Excel】Excel中将日期格式转换为文本格式,并按日期显示。

【问题需求】 在使用excel进行数据导入的过程中&#xff0c; 有的软件要求日期列必须是文本格式。 但是直接将日期列的格式改为文本后&#xff0c;显示一串数字&#xff0c;而不按日期显示。 进而无法导入使用。 【解决方法】 使用【TXET】函数公式进行处理&#xff0c; 在单…

EDA数据跨网交换解决方案,一文了解

EDA数据通常与电子设计自动化相关&#xff0c;这是一种利用计算机辅助设计&#xff08;CAD&#xff09;软件来完成超大规模集成电路&#xff08;VLSI&#xff09;芯片的功能设计、综合、验证、物理设计等流程的技术。以下是一些会涉及到EDA数据的行业&#xff1a; 集成电路设计…

淘宝扭蛋机源码解析:功能实现与技术细节

随着在线购物和娱乐的融合&#xff0c;淘宝扭蛋机作为一种创新的购物娱乐方式&#xff0c;受到了广大用户的喜爱。本文将深入解析淘宝扭蛋机的源码&#xff0c;探讨其功能实现与技术细节&#xff0c;以期为开发者们提供一些有价值的参考。 一、功能实现 1.用户登录与注册 淘宝…

《深入浅出OCR》项目实战:基于CRNN的文字识别

基于CRNN的文本字符验证码识别 1项目介绍链接&#xff1a; 为方便大家快速上手OCR实战&#xff0c;本次实战项目采用开源框架PaddleOCR&#xff0c;大家可以参考官网文档快速了解基本使用&#xff0c;项目数据为2022 DCIC赛题中提供的验证码数据集&#xff0c;大家可以参考其他…

圈子社区系统源码 开源 多端圈子社区论坛系统 社区圈子管理系统

介绍 圈子论坛小程序&#xff0c;是一款为用户提供交流分享、互动沟通的平台。在这个小程序中&#xff0c;用户可以轻松地加入各种不同兴趣爱好的圈子&#xff0c;与志同道合的朋友们交流互动。圈子论坛小程序不仅仅是一个简单的社交工具&#xff0c;更是一个打开新世界大门的…

el-table 固定前n行

el-table 固定前n行 第一种&#xff0c;通过设置前几行粘性布局 <el-table:data"tableData2"borderheight"calc(98% - 40px)"// 设置行样式:row-class-name"TableRowClassName"selection-change"handleSelectionChange" ><…

在 Java 项目中扫描识别图片中的文字(详细教程)

目录 需求&#xff1a; 步骤&#xff1a; 1、maven配置&#xff08;pom.xml&#xff09;&#xff1a; 2、下载依赖文件&#xff1a; 3、代码&#xff1a; post进行测试&#xff1a; 测试图片&#xff1a; 测试结果&#xff1a; 需求&#xff1a; 上传图片文件进行扫描…

CentOS 9安装Kubernetes(k8s)集群

前言 1、版本说明 系统版本&#xff1a;CentOS 9 k8s版本&#xff1a;v1.29.5 docker版本&#xff1a;26.1.3 harbor&#xff1a;v2.9.4 2、提前准备好1台虚拟机&#xff0c;可以参考博客&#xff1a;Vmware 17安装 CentOS9 3、虚拟机提前安装好docker&#xff0c;参考博客&a…

微信小程序多端框架打包后发布到华为市场

app上架华为应用市场 一、android 发布到华为应用市场 1、华为应用市场注册开发者账号 https://developer.huawei.com/consumer/cn/?ha_sourcesem&ha_sourceId89000605 2、进行企业认证 3、app隐私弹窗 miniapp-privacy.json 1、协议弹窗内容&#xff1a; {"tit…

C语言中的整型提升

一. 简介 本文来简单学习一下&#xff0c;C语言中的整型提升。 二. C语言中的整型提升 1. 什么是整型提升&#xff1f; C语言中的算数运算表达式总是以整型的精度进行的&#xff0c;为了获得这个精度&#xff0c;表达式的字符和短整型操作数在使用之前被隐式转换为普通类型…

Linux中Apache网站基于Http服务的访问限制(基于地址/用户)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f468;‍&#x1f4bb;Linux高级管理专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月3日11点44分 &#x1f004;️文章质量&#xff1a;95分 为了更好地控制对网站资源的访问&#xff0c;可…

谈谈JDK 漏洞 6260652

JDK 漏洞 6260652 在看ArrayList源码的过程中 发现带参构造里有一个注释&#xff1a; // c.toArray might (incorrectly) not return Object[] (see 6260652) public ArrayList(Collection<? extends E> c) {elementData c.toArray();if ((size elementData.length) …

动物收容所

题目链接 动物收容所 题目描述 注意点 若没有可以收养的动物&#xff0c;则返回[-1,-1]收纳所的最大容量为20000编号随着收养动物的增加自增 解答思路 利用队列先进先出的特点将猫和狗分别存进两个队列中&#xff0c;关键是dequeueAny这个方法中如果此时猫和狗的队列中都有…

演讲全文|林涛:MongoDB助力智能制造出海控本增效

5月29日-30日在上海世博中心举办的亚马逊云科技中国峰会圆满结束。本文整理了MongoDB北亚区方案与咨询总监林涛在白金讲堂的演讲全文&#xff0c;就《MongoDB助力智能制造出海控本增效》话题与大家共同探讨。 白金讲堂演讲视频 从全球经济竞争的角度看&#xff0c;中国制造业…

C++标准模板(STL)- 迭代器库-迭代器适配器- 逆序遍历的迭代器适配器 (二)

迭代器库-迭代器原语 迭代器库提供了五种迭代器的定义&#xff0c;同时还提供了迭代器特征、适配器及相关的工具函数。 迭代器分类 迭代器共有五 (C17 前)六 (C17 起)种&#xff1a;遗留输入迭代器 (LegacyInputIterator) 、遗留输出迭代器 (LegacyOutputIterator) 、遗留向前…

网站安全小白也能搞定的SSL证书安装免费方法

大家都知道&#xff0c;部署一个网站&#xff0c;除了购买域名&#xff0c;现在基本标配SSL证书。 我们以aliyun为例 大家看到这个&#xff0c;收费的SSL证书几千-几万1年不等。这时候&#xff0c;你就会想有没有免费的可以搞。linux老鸟都知道&#xff0c; Let’s Encrypt 、…

Megapoly.Art - Mechanic Shop Pack

Megapoly.art很高兴推出“汽车机械师包”。这个模块化包包括创建汽车机械师场景所需的一切,从简单的工具到先进的机器,包括路虎卫士的额外内容。 移动友好型低多边形建模和优化的纹理。 包信息 总计:129个预制件 - 5个独特的机器,21个建筑预制件,98个道具和奖励内容路虎(…

JVM类加载机制和双亲委派

类加载机制 java文件需要编译成字节码文件(.class文件)&#xff0c;jvm是通过类加载机制&#xff0c;将.class文件加载进内存&#xff0c;经过验证连接->初始化直到使用该对象的过程就是类加载机制&#xff0c;当new对象的时候&#xff0c;jvm首先去常量池寻找该类的符号引用…

LabVIEW电路板性能与稳定性测试系统

LabVIEW电路板性能与稳定性测试系统 概述&#xff1a; 开发基于LabVIEW的电路板性能与稳定性测试系统&#xff0c;通过集成多种测试仪器&#xff0c;实现对电路板的电气性能和长期稳定性的全面评估。系统涵盖了电压、电流、温度等多项参数的监测&#xff0c;并具备自动化测试…