Python网络编程之Socket(套接字)

news2025/3/14 20:49:27

文章目录

  • 一、Socket概念
  • 二、套接字的发展史及分类
  • 三、Socket的使用
      • 语法格式(基于TCP协议)
      • 1.基于TCP协议的套接字(socket)编程
        • 半连接池
      • 2.基于UDP协议的套接字(socket)编程
        • 也可以使用服务端只接收客户端消息
  • 黏包现象

一、Socket概念

Socket套接字,一种独立于协议的网络编程接口,就是对网络中不同主机上的应用进程之间进行双向通信的端点。
TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种端点我们叫做套接字(Socket)。

IP层的IP地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用IP地址+协议+端口号唯一标示网络中的一个进程。能够唯一标示网络中的进程后,它们就可以利用socket进行通信了

python中,我们利用Socket套接字来实现网络通信,可以说套接字是实现网络编程进行数据传输的一种技术手段。
Socket用于描述IP地址和端口,应用程序通常通过’套接字’相网络发出请求或者应答网络请求。
Socket主要是基于应用层和传输层之间,是一个中间的抽象层,功能是将复杂的TCP/IP协议族隐藏在Socket接口后面。
应用程序通过套接字发送或接收数据,socket模块针对服务器端和客户端Socket进行像对文件一样的打开、读写和关闭等操作。
套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

在这里插入图片描述

二、套接字的发展史及分类

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

  • 基于文件类型的套接字家族:
    套接字家族的名字:AF_UNIX

    unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

  • 基于网络类型的套接字家族:
    套接字家族的名字:AF_INET

    (还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

三、Socket的使用

通过指定地址簇和socket类型来进行创建。

地址簇描述
Socket.AF_UNIX只能够用于单一的Unix系统进程间通信
Socket.AF_INET服务器之间网络通信IPv4
Socket.AF_INET6IPv6
Socket类型描述
Socket.SOCK_STREAM流式socket,for TCP
Socket.SOCK_DGRAM数据报式socket,for UDP
Socket.SOCK_RAW原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

服务器与客户端交互过程:
在这里插入图片描述

语法格式(基于TCP协议)

									'''服务端'''

import socket
'''基于TCP协议的套接字(Socket)编程'''
'''以后养成一个查看源码编写代码的思路!!!!'''

'''服务端比客户端先运行,服务端先运行然后等待客户端连接'''

# 1.产生一个socket对象并指定采用的通信版本和协议(括号内不写默认就是TCP协议)
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
'''
AF_INET, type=SOCK_STREAM   AF_INET, type=SOCK_DGRAM
基于TCP协议                  基于UDP协议
'''

# 2.绑定IP地址(ip)和端口号(port)(需要用元组的形式)
'''def bind(self, __address: _Address | bytes) -> None: ...'''
# 绑定的IP地址可以省略,代表绑定本机,第一个参数为ip地址,第二个参数为端口号
server.bind(('127.0.0.1', 8000))
'''127.0.0.1为本地回环地址,只有自己电脑可以访问'''

# 3.服务器做监听,也称为半连接池(需要用int类型,服务器能够同时等待客户端的数量)(排队数量不包含正在执行的)
'''    def listen(self, __backlog: int = ...) -> None: ...'''
# listen有一个参数,是一个数值,参数越大,以后可以连接的客户端越多,参数越小链接的客户端越小
server.listen(3)
print('form Listen')


# 4.等待接收客户端的连接请求
'三次握手'
sock, addr = server.accept()  # return sock,addr
# 运行到这里会等待客户端发送信息才继续下面的运行
'''sock就是双向通道,addr就是客户端地址'''
print('等待完成!')

# 5.接收客户端发送过来的消息,(接收到的类型是bytes类型,二进制的)
'''def recv(self, __bufsize: int, __flags: int = ...) -> bytes: ...'''
data = sock.recv(1024)  # 括号内代表的是一次接收最多1024个字节
'''recv()接收     send()发送'''
print('接收到了客户端的数据:',data)

# 6.给客户端发送消息,注意消息必须是bytes类型的
sock.send(data.upper())  # 我这里就只是给客户端发送的消息转成大写

# 7.关闭双向通道
'四次挥手'
sock.close()

# 8.关闭服务器
server.close()


print('==============================')

									'''客户端'''
import socket
'''运行程序时一定要确保先运行了服务器,之后才是客户端'''
# 1.生成socket对象指定类型和协议
client1 = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)

# 2.通过IP地址和端口号连接服务端
'''def connect(self, __address: _Address | bytes) -> None: ...'''
client1.connect(('127.0.0.1', 8000))

# 3.直接给服务端发送消息
client1.send('hello world'.encode('utf-8'))

# 4.接收服务端发送过来的消息
data = client1.recv(1024)
print('收到服务端发来的消息:', data.decode('utf-8'))

# 5.断开与服务端的链接
client1.close()

1.基于TCP协议的套接字(socket)编程

TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

服务端:

	import socket

# 生成一个socket对象,设定类型和协议
server1 = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)

# 为socket设置IP地址,端口号
server1.bind(('127.0.0.1', 8080))

# 给服务器添加同时监听几个客户端,
server1.listen(3)

while True:
    # 等待客户端发来消息
    sock, addr = server1.accept()
    # sock双向通道,addr客户端地址
    while True:
        try:
            # 避免用户断开后,直接报错,自动捕获异常
            # 接收客户端发来的消息 二进制
            data = sock.recv(2048)
            print('接收到了客户端发来的消息:', data.decode('utf-8'))
            # 给客户端回复消息
            mag = input('请输入回复的消息>>>:').strip()
            sock.send(mag.encode('utf-8'))

        except Exception as f:
            print(f)
            break

# 关闭双向通道
sock.close()

# 断开服务器链接
server1.close()

客户端:

	import socket

# 生成一个socket对象,设置类型和协议
client4 = socket.socket(family = socket.AF_INET,type=socket.SOCK_STREAM)

# 连接到服务器
client4.connect(('127.0.0.1',8080))

while True:
    # 向服务器发送消息
    mag = input('请输入发送的消息>>>:').strip()

	if len(mag) == 0:
		print('请输入有效信息!')
		continue

    if mag == 'yes':
        print('已断开与服务器连接!')
        break

    client4.send(mag.encode('utf-8'))  # 转码

    # 接收服务器回应的消息 字节
    data = client4.recv(2048)
    print('接收到了服务器发来的消息:',data.decode('utf-8'))  # 解码

    print('是否不在回复,断开连接?,请输入yes即可!')

# 断开连接
client4.close()

有时候我们在重启服务端时,会出现端口被占用的情况。这是因为虽然连接已经关闭,但是端口还没来得及释放。
在这里插入图片描述
两种解决方案:
* 更换端口。
* bind绑定IP之前添加一个参数,来达到端口复用的目的。

import os

server = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)

server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

# 绑定ip地址和端口,127.0.0.1代表回环地址,只能当前计算机访问
server.bind(('127.0.0.1',8080))
半连接池
	半连接池server.listen(5)
	意思就是同时可以运行五个客户端 如果多于五个则会报错
	需要等待前面五个客户端其中一个结束 则会有多余的位置给到第六个

2.基于UDP协议的套接字(socket)编程

UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

udp是无连接的,所以发送数据前不需要先建立连接。
我们可以使用多个客户端与服务端进行数据发送,服务端可以逐个回复
udp发送数据采用的是数据报模式,数据会一次性全部发过去,如果未接收到也不会保存,安全性没有保障,但传输速率较快。

服务端:

	import socket
'''基于UDP协议的套接字(socket)编程'''

# 生成一个socket对象 设置类型和协议
server = socket.socket(family = socket.AF_INET,type = socket.SOCK_DGRAM)
'''这里因为要设置成UDP协议,所以type = socket.SOCK_DGRAM'''

# 设置服务器IP地址及端口号
server.bind(('127.0.0.1',8848))

while True:
    # 接受客户端发送来的信息,以及发送者的ip以及端口(UDP不需要建立连接)
    data,addr = server.recvfrom(2048)
    print(f"收到客户端{addr}发来的消息:",data.decode('utf-8'))

    # 向发送者回复信息
    mag = input('请输入回复的消息>>>>:').strip()
    server.sendto(mag.encode('utf-8'), addr)

客户端:

	import socket

# 生成一个socket对象 设置类型和协议
client = socket.socket(family = socket.AF_INET,type = socket.SOCK_DGRAM)

server_ip = ('127.0.0.1',8848)  # 写好的ip地址和端口
# 无需和服务端建立连接

while True:
    mag = input('请输入发送的消息>>>:').strip()
    # 无需判断是否为空,因为UDP每次发送都不只是单纯的数据,还有ip和端口信息

    # 直接向写好的ip和端口发送数据
    client.sendto(mag.encode('utf-8'),server_ip)

    # 接收它的返回值
    data,addr = client.recvfrom(2048)
    print(f"接收到了{addr}的消息:",data.decode('utf-8'))
也可以使用服务端只接收客户端消息

服务端:

	import socket
server = socket.socket(family = socket.AF_INET,type = socket.SOCK_DGRAM)

server.bind(('127.0.0.1',8888))

# 无需建立连接

while True:
    data,addr = server.recvfrom(2048)
    print(f"接收到了发送者{addr}发来的消息:",data.decode('utf-8'))

客户端:

	import socket

client = socket.socket(family = socket.AF_INET,type = socket.SOCK_DGRAM)

# 无需建立连接

while True:
    # 直接给对应的ip地址和端口号发送信息
    mag = input('请输入发送的消息>>>:').strip()
    client.sendto(mag.encode('utf-8'),('127.0.0.1',8888))

黏包现象

	1.服务端连续执行三次recv
	2.客户端连续执行三次send
	问题:服务端一次性接收到了客户端三次的消息 该现象称为"黏包现象"
  
黏包现象产生的原因
	1.不知道每次的数据到底多大
	2.TCP也称为流式协议:数据像水流一样绵绵不绝没有间隔(TCP会针对数据量较小且发送间隔较短的
	多条数据一次性合并打包发送)
 
避免黏包现象的核心思路\关键点
		如何明确即将接收的数据具体有多大
	
ps:如何将长度变化的数据全部制作成固定长度的数据

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

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

相关文章

机器学习,神经网络中,自注意力跟卷积神经网络之间有什么样的差异或者关联?

如图 6.38a 所示,如果用自注意力来处理一张图像,假设红色框内的“1”是要考虑的像素,它会产生查询,其他像素产生 图 6.37 使用自注意力处理图像 键。在做内积的时候,考虑的不是一个小的范围,而是整张图像的…

力扣每日一题45:跳跃游戏

题目描述&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返…

C语言实现// 输入一个英文句子,以‘ . ’结束,统计句子中包含的字符个数

完整代码&#xff1a; // 输入一个英文句子&#xff0c;以‘ . ’结束&#xff0c;统计句子中包含的字符个数 #include<stdio.h>int main(){char ch;int length0;printf("请输入一个英文句子\n");while (chgetchar()!.){length;}printf("字符个数是&…

Qt/C++开源作品45-CPU内存显示控件/和任务管理器一致

一、前言 在很多软件上&#xff0c;会在某个部位显示一个部件&#xff0c;专门显示当前的CPU使用率以及内存占用&#xff0c;方便用户判断当前程序或者当前环境中是否还有剩余的CPU和内存留给程序使用&#xff0c;在不用打开任务管理器或者资源查看器的时候直接得知当前系统的…

大模型,重构自动驾驶

文&#xff5c;刘俊宏 编&#xff5c;王一粟 大模型如何重构自动驾驶&#xff1f;答案已经逐渐露出水面。 “在大数据、大模型为特征&#xff0c;以数据驱动为开发模式的自动驾驶3.0时代&#xff0c;自动驾驶大模型将在车端、云端上实现一个统一的端到端的平台管理。”毫末智…

【线性表的查找,线性表插入,线性表的删除,线性表的链式表示和实现】

文章目录 线性表的查找线性表插入线性表的删除线性表的链式表示和实现1.单链表&#xff0c;双链表&#xff0c;循环列表2.头指针&#xff0c;头结点和首元结点3.链表的存储结构特点 线性表的查找 int LocateElem(Sqlist L,ElemType e){ //在线性表L中查找值为e的数据元素&…

jmeter(三十三):阶梯线程组Stepping Thread Group,并发线程Concurrency Thread Group

Stepping Thread Group参数详解 this group will start:表示总共要启动的线程数;若设置为 100,表示总共会加载到 100 个线程first,wait for:从运行之后多长时间开始启动线程;若设置为 0 秒,表示运行之后立即启动线程then start:初次启动多少个线程;若设置为 0 个,表示…

实验室设备modbus小结

背景&#xff1a; 大概花1个月&#xff0c;后端代码量再1W行多点&#xff0c;不同厂商的指令不同需要定制化开发。参与了设备的数据采集工作&#xff0c;当然常规的设备管理、权限就不重点展开。 都是物联网相关&#xff0c;但是还是有所不同。 之前做过海尔的U home相关的项目…

京东AIGC实战项目复盘;第一门AI动画系统课程;百川智能启动2024校园招聘;Kaggle 2023 AI前沿报告 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f525; 李彦宏宣布「文心大模型4.0」正式发布&#xff0c;并开启邀请测试 10月17日&#xff0c;李彦宏在百度世界2023上宣布「文心大模型4.0」…

微信小程序 —— 会议OA项目首页布局与Mock数据交互

14天阅读挑战赛如果世界上有奇迹&#xff0c;那一定是努力的另一个名字。 目录 一、小程序布局 1.1 Flex布局 1.2 Flex属性 二、OA会议首页搭建 2.1 首页底部菜单 2.2 创建后端结口 2.3 Mock模拟数据 2.4 首页轮播图搭建 2.5 首页内容搭建 一、小程序布局 1.1 Flex布…

SpringBoot+Mybatis实现多数据源+分页

1 主要依赖版本 &#xff08;1&#xff09;SpringBoot 2.7.8 &#xff08;2&#xff09;Mybatis 2.2.2 &#xff08;3&#xff09;Pagehelper 1.3.0 &#xff08;4&#xff09;MySQL 8.0.26 &#xff08;5&#xff09;Oracle 11.2.0.3 2 概述 &#xff08;1&#xff09;…

Linux内核8. 进程地址空间

进程地址空间也就是每个进程所使用的内存&#xff0c;内核对进程地址空间的管理&#xff0c;也就是对用户态程序的内存管理。 主要内容&#xff1a; 地址空间(mm_struct)虚拟内存区域(VMA)地址空间和页表 1. 地址空间(mm_struct) 地址空间就是每个进程所能访问的内存地址范围…

React高级特性之RenderProps

一、概念 renderProps是另外一个能实现类似于HOC这种多个组件抽离公共组件逻辑的方式。 二、例子 import React from react import PropTypes from prop-typesclass Mouse extends React.Component {constructor(props) {super(props)this.state { x: 0, y: 0 }}handleMouse…

日志技术快速入门

1、创建Maven项目 这里不再说如何创建Maven项目 2、导入相关依赖 <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.12</version></dependency>3、创建配置文件 在re…

Spring源码解析——事务增强器

正文 上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的&#xff0c;也讲解了Spring是如何将有配置事务的类配置上事务的&#xff0c;实际上也就是用了AOP那一套&#xff0c;也讲解了Advisor&#xff0c;pointcut验证流程&#xff0c;至此&#xff0c;事务的初始化工…

强化学习------Policy Gradient算法

目录 简介PG算法原理效果&#xff1a;参考 简介 之前的QLearning DQN Sarsa都是通过计算动作得分来决策的&#xff0c;我们是在确定了价值函数的基础上采用某种策略&#xff0c;即Value-Based&#xff0c;通过先算出价值函数&#xff0c;再去做决策。而Policy Gradient算法是一…

云计算:shell脚本

shell脚本&#xff0c;会极大减少重复性工作&#xff0c;缩短很大时间。 脚本每个人都可以不一样&#xff0c;只要实现就可以。 注意&#xff1a;要多思考&#xff0c;把思路锻炼好。以后就可以写各种程序。 shell语言 学完shell之后&#xff0c;对Linux理解更深刻&#xff…

在调试器下看微信[如何耗电]

在今天这样干什么都离不开手机的时代里&#xff0c;手机的待机时间太重要了。特别是对于我这个不喜欢带充电宝出门的人来说&#xff0c;一旦看到手机电量低于20%&#xff0c;立刻就精神紧张了&#xff0c;因为一切信息都在手机里&#xff0c;如果手机没电&#xff0c;那么就失联…

[SQL | MyBatis] MyBatis 简介

目录 一、MyBatis 简介 1、MyBatis 简介 2、工作流程 二、入门案例 1、准备工作 2、示例 三、Mapper 代理开发 1、问题简介 2、工作流程 3、注意事项 4、测试 四、核心配置文件 mybatis-config.xml 1、environment 2、typeAilases 五、基于 xml 的查询操作 1、…

通过stream对list集合中对象的多个字段进行去重

记录下通过stream流对list集合中对象的多个字段进行去重&#xff01; 举个栗子&#xff0c;对象book&#xff0c;我们要通过姓名和价格这两个字段的值进行去重&#xff0c;该这么做呢&#xff1f; distinct&#xff08;&#xff09;返回由该流的不同元素组成的流。distinct&am…