Sockets (套接字)的使用

Sockets (套接字)编程是连接网络上两个节点以相互通信的一种方式。一个套接字(节点)侦听IP上的特定端口,而另一个套接字则连接到另一个。当客户端连接到服务器时,服务器形成侦听器套接字。

1 创建套接字

# create an INET, STREAMing socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# now connect to the web server on port 80 - the normal http port
s.connect(("www.python.org", 80))

当连接完成时,套接字s可以用于发送对页面文本的请求。同一个套接字将读取回复,然后被销毁。客户端套接字通常只用于一个交换机(或一小组顺序交换机)。

web服务器中发生的事情有点复杂。首先,web服务器创建一个“服务器套接字”:

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)

需要注意是:我们使用了socket.gethostname(),以便套接字对外可见。如果我们使用了.bind(('localhost',80))或s.bind('27.0.0.1',80),我们仍然会有一个“服务器”套接字,但只能在同一台机器中看到。s.bind(('',80))指定计算机拥有的任何地址都可以访问套接字。

为“众所周知”的服务(HTTP、SNMP等)保留少量端口。如果你在玩,使用一个很好的大数字(4位数)。

最后,要侦听的参数告诉套接字库,我们希望它在拒绝外部连接之前将有多达5个连接请求(正常最大值)在排队。如果代码的其余部分写得正确,那就足够了。

现在我们有了一个“服务器”套接字,在端口80上侦听,可以进入web服务器的主循环:

while True:# accept connections from outside(clientsocket, address) = serversocket.accept()# now do something with the clientsocket# in this case, we'll pretend this is a threaded serverct = client_thread(clientsocket)ct.run()

实际上,这个循环有三种通用的工作方式——调度一个线程来处理clientsocket,创建一个新进程来处理clientsocket,或者重组这个应用程序以使用非阻塞套接字,并使用select在我们的“服务器”套接字和任何激活的clientsocket之间进行多路复用。这就是“服务器”套接字所做的一切。它不发送任何数据。它没有接收到任何数据。它只生成“客户端”套接字。每个客户端套接字都是为了响应其他“客户端”套接字对我们绑定的主机和端口执行connect()操作而创建的。创建该客户端套接字后,我们将返回侦听更多连接。这两个“客户端”可以自由地聊天——他们正在使用一些动态分配的端口,当会话结束时,这些端口将被回收。

2 使用套接字

首先要注意的是,web浏览器的“客户端”套接字和web服务器的“客户端”套接字是完全相同的。也就是说,这是一次“对等”对话。或者换言之,作为设计师,你必须决定谈话的礼仪规则是什么。通常,连接套接字通过发送请求或登录来启动会话。

现在有两组动词可用于交流。您可以使用send和recv,也可以将客户端套接字转换为类似beast的文件并使用read和write。后者是Java表示其套接字的方式。这些都是缓冲的“文件”,一个常见的错误是写一些东西,然后读取以获得回复。如果没有刷新,您可能会永远等待回复,因为请求可能仍在输出缓冲区中。

现在我们来谈谈套接字的主要障碍——在网络缓冲区上的发送和接收操作。它们不一定能处理你交给它们(或期望它们)的所有字节,因为它们的主要关注点是处理网络缓冲区。通常,当相关联的网络缓冲区已被填充(send)或清空(recv)时,它们会返回。然后,它们会告诉您它们处理了多少字节。你有责任再次通知它们,直到你的信息得到完全处理。

当recv返回0个字节时,表示对方已关闭(或正在关闭)连接。您将不会再收到此连接上的任何数据。

像HTTP这样的协议只使用一个套接字进行一次传输。客户端发送一个请求,然后读取一个回复。就是这样。套接字被丢弃了。这意味着客户端可以通过接收0个字节来检测回复的结束。

但是,如果您计划重用套接字进行进一步的传输,您需要意识到套接字上没有EOT,即如果 socket 的 send 或 recv 在处理 0 字节后返回,连接已经断开。如果连接没有断开,您可能会永远等待recv,因为套接字不会告诉您(目前)没有更多内容可供读取。因此,socket的消息必须是固定长度的,或者是限定了长度的,或者标明了长度,或者以关闭连接结束。

假设您不想结束连接,最简单的解决方案是固定长度的消息:

class MySocket:"""demonstration class only- coded for clarity, not efficiency"""def __init__(self, sock=None):if sock is None:self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)else:self.sock = sockdef connect(self, host, port):self.sock.connect((host, port))def mysend(self, msg):totalsent = 0while totalsent < MSGLEN:sent = self.sock.send(msg[totalsent:])if sent == 0:raise RuntimeError("socket connection broken")totalsent = totalsent + sentdef myreceive(self):chunks = []bytes_recd = 0while bytes_recd < MSGLEN:chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))if chunk == b'':raise RuntimeError("socket connection broken")chunks.append(chunk)bytes_recd = bytes_recd + len(chunk)return b''.join(chunks)

3 断开连接

严格地说,你应该在关闭套接字之前对其使用shutdown。shutdown是对另一端套接字的建议。根据你传递的论点,它可能意味着“我不会再发送了,但我仍然会听”。然而,大多数套接字库对于程序员来说太习惯了,所以close()通常与shutdown()相同;因此,在大多数情况下,不需要显式关闭。

有效使用shutdown的一种方法是在类似HTTP的交换中。客户端发送一个请求,然后执行shutdown(1)。这一消息会告诉服务器“此客户端已完成发送,但仍然可以接收”。 服务器可以通过接收0字节来检测“EOF”。它可以假设它有完整的请求。服务器发送回复。如果发送成功,那么客户端实际上仍在接收。

4 非阻塞套接字

在Python中,使用socket.setblocking(False)使其成为非阻塞的。在C中,它更复杂。主要的区别在于发送、接收、连接和接受可以在不做任何事情的情况下返回。

使用select。

在C语言中,编码选择相当复杂。在Python中,这是小菜一碟,但它与C版本非常接近,如果您理解Python中的select,那么在C中使用它就不会有什么问题:

ready_to_read, ready_to_write, in_error = \select.select(potential_readers,potential_writers,potential_errs,timeout)

通过选择三个列表:

  • 第一个列表包含想要尝试读取的所有套接字;
  • 第二个是想要尝试写入的所有套接字;
  • 最后一个(通常为空)是检查错误的套接字。

一个套接字可以进入多个列表。这会使select调用被阻止,但可以通过给出一个超时时间来解决该问题。

作为回报,您将获得三个列表。它们包含实际可读、可写和出错的套接字。这些列表中的每一个都是您传入的相应列表的子集(可能为空)。

如果一个套接字在输出可读列表中,那么该套接字上的recv会返回一些信息。写列表与读列表一样。

如果您有一个“服务器”套接字,请将其放在potential_readers列表中。如果它出现在可读列表中,你的accept(几乎肯定)会起作用。如果你已经创建了一个新的套接字来连接到其他人,请将其放在potential_writers列表中。如果它出现在可写列表中,那么它很有可能已经连接。

事实上,即使有阻塞的套接字,select也很方便。这是确定是否要阻塞套接字的一种方法——当缓冲区中有内容时,套接字返回可读状态。然而,这仍然无助于确定另一端是否完成,或者只是忙于其他事情的问题。

可移植性:在Unix上,select同时适用于套接字和文件。不要在Windows上尝试此操作。在Windows上,select仅适用于套接字。还要注意,在C语言中,许多更高级的套接字选项在Windows上的操作方式不同。

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

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

相关文章

矩阵的迹(Trace)

矩阵的迹&#xff08;Trace&#xff09; flyfish 矩阵的迹&#xff08;Trace&#xff09;是指一个方阵&#xff08;即行数和列数相同的矩阵&#xff09;对角线元素之和。就是在一个正方形的数字表格里&#xff0c;沿着从左上角到右下角的对角线&#xff0c;把这条线上所有的数…

星期六-本周的学习内容全面复习和总结!

本周共学习以下的基础内容&#xff1a; 样本空间和事件的集合表示&#xff1b; 数列极限的定义 随机事件的概率 对于本周的学习内容进行全面复习和总结是一个重要的学习过程&#xff0c;这有助于巩固记忆和提高理解能力。以下是一些步骤和建议&#xff1a; 收集资料&#x…

【嵌入式DIY实例】-Nokia 5110显示DS3231 RTC数据

Nokia 5110显示DS3231 RTC数据 文章目录 Nokia 5110显示DS3231 RTC数据1、硬件准备与接线2、代码实现本文将介绍如何使用 ESP8266 NodeMCU 板和 DS3231 RTC 模块制作一个简单的数字实时时钟,其中可以使用连接到 NodeMCU 的两个按钮设置时间和日期,并将它们打印在诺基亚 5110 …

STM32学习 BKP

BKP就是备份寄存器的意思&#xff0c;听名字就知道它的作用就是用来备份数据的。下面是手册当中的描述。备份寄存器是42个16位的寄存器&#xff0c;可用来存储84个字节的用户应用程序数据。他们处在备份域 里&#xff0c;当VDD电源被切断&#xff0c;他们仍然由VBAT维持供电。当…

【JavaEE精炼宝库】多线程(6)线程池

目录 一、线程池的概念及优势 1.1 线程池的概念&#xff1a; 1.2 线程池的优势&#xff1a; 二、工厂模式 三、标准库中的线程池 3.1 标准库线程池参数解释&#xff1a; 3.1.1 corePoolSize | maximumPoolSize&#xff1a; 3.1.2 keepAliveTime | unit&#xff1a; 3.1…

原型模式--深复制/浅复制

原型模式用于克隆复杂对象&#xff0c;由于new一个实例对象会消耗大部分时间&#xff0c;所以原型模式可以节约大量时间 1 public class Sheep implements Cloneable{2 private String name;3 private Date birth;4 public Sheep(String name, Date birth) {5 …

记一次全设备通杀未授权RCE的挖掘经历

想来上一次挖洞还在一年前的大一下&#xff0c;然后就一直在忙活写论文&#xff0c;感觉挺枯燥的&#xff08;可能是自己不太适合弄学术吧QAQ&#xff09;&#xff0c;所以年初1~2月的时候&#xff0c;有空的时候就又会挖一挖国内外各大知名厂商的设备&#xff0c;拿了几份思科…

【机器学习】基于Transformer架构的移动设备图像分类模型MobileViT

1.引言 1.1. MobileViT是什么&#xff1f; MobileViT是一种基于Transformer的轻量级视觉模型&#xff0c;专为移动端设备上的图像分类任务而设计。 背景与目的&#xff1a; MobileViT由Google在2021年提出&#xff0c;旨在解决移动设备上的实时图像分类需求。与传统的卷积神…

微信小程序的目录结构

微信小程序的目录结构主要包括以下几个部分&#xff0c;这些部分共同构成了小程序的基础框架和页面展示。以下是一个详细的目录结构介绍&#xff1a; 1. 根目录文件 app.js&#xff1a;小程序的主逻辑文件&#xff0c;用于监听并处理小程序的生命周期函数、全局变量等。这个文…

[leetcode] 双指针集锦(python实现)

在解题时&#xff0c;双指针的思想常常可以帮助我们优化解法的时间空间复杂度。接下来&#xff0c;我将通过两道LeetCode的题来给大家讲解双指针的使用方法。 文章目录 题目1&#xff1a;Two Sum题目2&#xff1a;Three Sum双指针思想的总结 题目1&#xff1a;Two Sum 题目描述…

Selenium 定位编辑框有span

当使用Selenium进行网页自动化测试时&#xff0c;定位一个包含span元素的编辑框可能会有些棘手&#xff0c;因为span通常用于对其他HTML元素进行分组或应用样式&#xff0c;而不一定是真正的可输入字段。不过&#xff0c;一旦我们确定了正确的策略&#xff0c;定位编辑框还是相…

AtomicInteger

1. 前言 AtomicInteger是Java中的一个原子整数类&#xff0c;它提供了一种在多线程环境下进行原子性操作的方法。所谓原子性操作是指不会被线程调度机制打断的操作&#xff1b;这些操作可以在可能被其他线程影响的情况下作为一个不可分割的整体执行。 在并发编程中&#xff0…

【Android面试八股文】Android中操作多线程的方式有哪些?

文章目录 1. 使用 `Thread` 和 `Runnable`2. `AsyncTask`3. `Handler` 和 `Looper`4. `HandlerThread`5. `ThreadPoolExecutor`6. `IntentService`7. `RxJava`8. `Coroutine`(协程)9. `WorkManager`在Android开发中,有多种方式可以进行多线程操作。以下是主要的几种方式: 1…

【日常记录】【vue】vite-plugin-inspect 插件的使用

文章目录 1、vite-plugin-inspect2、安装3、使用4、链接 1、vite-plugin-inspect vite-plugin-inspect 可以让开发者在浏览器端就可以看到vue文件编译后的代码、vue文件的相互依赖关系 2、安装 npm i -D vite-plugin-inspect// vite.config.ts import Inspect from vite-plugi…

LeetCode题练习与总结:最长连续序列--128

一、题目描述 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [100,4,200,1,3,2] 输出&…

SpringBootWeb 篇-入门了解 Spring Cache 、Spring Task 与 WebSocket 框架

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Spring Cache 概述 1.1 Spring Cache 具体使用 1.1.1 引入依赖 1.1.2 Spring Cache 相关注解的介绍 2.0 Spring Task 概述 2.1 cron 表达式 2.2 Spring Task 使用…

基于微信公众号开发h5的前端流程

1.首先公众号进行配置&#xff0c;必须要https域名 还有个txt文件&#xff0c;有弹框提示需要下载放在服务器上 前端处理code的代码封装 // 微信公众号授权 export function wxAuthorize(calback) {// 非静默授权&#xff0c;第一次有弹框 这里的回调页面就是放在服务器上微信…

c语言连接两个字符串

在C语言中&#xff0c;连接两个字符串可以使用 strcat 函数。这个函数将一个字符串复制到另一个字符串的末尾。使用 strcat 函数之前&#xff0c;需要确保目标字符串有足够的空间来容纳源字符串&#xff0c;否则可能会导致缓冲区溢出。 下面是一个使用 strcat 函数连接两个字符…

外贸推广渠道有哪些

外贸推广渠道多种多样&#xff0c;每一种都有其特定的优势和适用场景。以下是一些常见的外贸推广渠道&#xff0c;它们被广泛用于吸引国际客户、增加品牌曝光度和促进销售。 外贸B2B平台推广&#xff1a; 阿里巴巴国际站&#xff1a;作为全球知名的B2B平台&#xff0c;汇聚了大…

MFC工控项目实例之五CFile类读写系统参数

承接专栏《MFC工控项目实例之四在调试目录下创建指定文件夹》 实时保存输入的iPlotX坐标轴最小值、最大值到CFG.PAR文件&#xff0c;打开界面从CFG.PAR文件中实时读取保存的最小值、最大值在编辑框中显示。 1、SEAL_PRESSURE.h中添加代码 class CSEAL_PRESSUREApp : public CW…