【Python】【网络通信】基础知识

部署运行你感兴趣的模型镜像

网络编程就是如何在程序中实现两台计算机的通信。

一、IP地址、端口

1.IP地址

IP地址就像是我们的家庭住址一样,如果你要写信给一个人,你就要知道他(她)的地址,这样邮递员才能把信送到。计算机发送信息就好比是邮递员,它必须知道唯一的“家庭地址”才能不至于把信送错人家。只不过我们的地址是用文字来表示的,计算机的地址用二进制数字表示。 IP地址被用来给Internet上的电脑一个编号。

2.端口的概念

  • IP地址好比每个人的地址(门牌号),端口好比是房间号。必须同时指定IP地址和端口号才能够正确的发送数据。
  • IP地址好比为电话号码,而端口号就好比为分机号。

要注意:

端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。 

按端口号分类:

公认端口(Well Known Ports):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。

注册端口(Registered Ports):从1024到65535。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。

二、TCP、UDP协议

TCP 和 UDP 的优缺点无法简单地、绝对地去做比较:TCP 用于在传输层有必要实现可靠传输的情况;UDP 主要用于那些对高速传输和实时性有较高要求的通信或广播通信。TCP 和 UDP 应该根据应用的目的按需使用。

1.TCP

TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。

2.UDP

UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。

UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP

3.总结

  • TCP是面向连接的,传输数据安全,稳定,效率相对较低。
  • UDP是面向无连接的,传输数据不安全,效率较高。

三、TCP的三次握手、四次挥手

1.三次握手

TCP 的三次握手:就像 “打电话确认接通”

想象你给朋友打电话,要确认双方都能正常沟通,步骤是这样的:

  1. 你打过去(第一次握手)
    你拨号后说:“喂,能听到吗?”(发送连接请求:“我想连你,你准备好了吗?”)。

  2. 朋友回应(第二次握手)
    朋友听到后说:“能听到!你能听到我吗?”(回应请求:“我准备好了,你能收到我的回复吗?”)。

  3. 你再确认(第三次握手)
    你听到后说:“能听到!那我们开始聊吧~”(确认收到回应:“我收到了,现在可以正式通信了!”)。

三次握手结束后,你们俩就确认了 “双向都能收发消息”,通话(连接)正式建立。

2.四次挥手

TCP 的四次挥手:就像 “挂电话前说再见”

通话结束后,要礼貌地结束连接,确保双方都准备好断开,步骤是这样的:

  1. 你说 “我要挂了”(第一次挥手)
    你说:“我没话说了,准备挂电话啦~”(发送断开请求:“我这边数据发完了,想断开连接。”)。

  2. 朋友说 “收到,我确认下”(第二次挥手)
    朋友说:“好的,我知道你要挂了,我看看还有没有没说完的……”(回应请求:“我收到你的断开请求了,等我处理完剩余数据。”)。

  3. 朋友说 “我也说完了,挂吧”(第三次挥手)
    朋友处理完后说:“我也没话说了,你可以挂了~”(发送断开通知:“我这边数据也发完了,准备断开。”)。

  4. 你说 “好的,挂了”(第四次挥手)
    你说:“收到!那我挂啦~”(确认通知:“我收到你的断开通知了,断开连接吧。”)。

四次挥手结束后,双方确认 “都没有数据要发了”,通话(连接)正式断开。

四、socket()套接字编程

1.socket()介绍

Socket编程封装了常见的TCP、UDP操作,可以实现非常方便的网络编程。

socket套接字编程表示‘打开了一个网络’,socket 就是网络程序之间的 “通信通道”,语法为:
socket.socket(family[,type[,proto]])
    ① family:是套接字家族,可以理解为:通信方式的分类,可以用AF_UNIX或者AF_INET
        AF_INET就像是发快递,用来处理‘跨网络通信’,需要‘IP+端口号’
        AF_UNIX就像是和同桌传纸条,负责同一台电脑内部的程序之间通信
    ② type:是是套接字类型,分为SOCK_STREAM和SOCK_DGRAM
        SOCK_STREAM:TCP--快但是不稳
        SOCK_DGRAM:UDP--慢但是稍稳
    ③ protoclo:一般不填,默认为 0

2.服务器端的套接字函数

① s.bind()

        绑定地址到套接字,用元组的形式

② s.listen()

        开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。

③ s.accept()

        被动接受TCP客户端连接,(阻塞式)等待连接的到来

3.客户端套接字函数

 s.connect()

        主动初始化TCP服务器连接,。一般address的格式为元组

4.公共用途的常用套接字函数

(一)TCP用的

① s.recv()

        接收TCP数据,数据以字符串形式返回

② s.send()

        发送TCP数据

(二)UDP用的

① s.recvfrom()

        接收UDP数据,与recv()类似

② s.sendto()

        发送UDP数据,将数据发送到套接字

五、UDP编程

1.服务器接收数据最简单的代码例子

'''
UDP编程时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发送数据包
UDP编程数据传输不可靠,但是传输速度很快
socket套接字编程表示‘打开了一个网络’,socket 就是网络程序之间的 “通信通道”,语法为:
socket.socket(family[,type[,proto]])
    family:是套接字家族,可以理解为:通信方式的分类,可以用AF_UNIX或者AF_INET
        AF_INET就像是发快递,用来处理‘跨网络通信’,需要‘IP+端口号’
        AF_UNIX就像是和同桌传纸条,负责同一台电脑内部的程序之间通信
    type:是是套接字类型,分为SOCK_STREAM和SOCK_DGRAM
        SOCK_STREAM:TCP--快但是不稳
        SOCK_DGRAM:UDP--慢但是稍稳
    protoclo:一般不填,默认为 0
'''

#UDP接受数据
from socket import *
s=socket(AF_INET,SOCK_DGRAM)  #创建了套接字
#绑定接收信息的端口
s.bind(('127.0.0.1',8888))  #这是在绑定端口,IP地址和端口号,要用元组的形式
print("等待接收数据!")
redata=s.recvfrom(1024)  #1024表示本次接受的最大字节数
#recvfrom()用于接收UDP数据,这个方法会阻塞程序执行,直到收到数据为止
#返回的是一个元组,包含收到的数据和发送方的地址信息
print(redata)
print(f"收到远程信息:{redata[0].decode("gbk")},from{redata[1]}")
#redata[0]是接收到的原始字节数据,redata[1]是发送方的地址信息,格式为(IP地址,端口号)
#decode('gbk')将字节数据解码为字符串
s.close()  #操作完成后关闭套接字,释放资源

2.客户端发送数据最简单的例子

from socket import *
s=socket(AF_INET,SOCK_DGRAM) #创建套接字
addr=('127.0.0.1',8888)  #准备接收方的地址
data=input("请输入...")
#发送数据
s.sendto(data.encode("gbk"),addr)
#发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。
s.close()

3.服务器持续接收数据的例子

from socket import *
#创建套接字
s=socket(AF_INET,SOCK_DGRAM)
#绑定接受数据的端口
s.bind(('127.0.0.1',8800))  #绑定端口要用元组的形式
print("等待接收数据!")

while True:
    # 接收数据,返回元组
    redata=s.recvfrom(1024)
    recv_content=redata[0].decode('gbk')
    print(f"收到远程信息:{recv_content},from{redata[1]}")
    if recv_content=="88":
        print("聊天结束!")
        break

s.close()

4.客户端持续发送数据的例子

from socket import *
#创建套接字
s=socket(AF_INET,SOCK_DGRAM)
#创建接受的地址(IP地址,端口)
addr=('127.0.0.1',8800)

while True:
    #创建发送的内容
    data=input("请输入...")
    s.sendto(data.encode('gbk'),addr)
    if data == '88':
        print('聊天结束!')
        break

s.close()

5.多线程服务端自由通信

from socket import *
from threading import Thread

def recv_data():
    while True:
        # 接收数据,返回元组
        redata = s.recvfrom(1024)
        recv_content = redata[0].decode('gbk')
        print(f"收到远程信息:{recv_content},from{redata[1]}")
        if recv_content == "88":
            print("聊天结束!")
            break

def send_data():
    # 创建接受的地址(IP地址,端口)
    addr = ('127.0.0.1', 8800)
    while True:
        # 创建发送的内容
        data = input("请输入...")
        s.sendto(data.encode('gbk'), addr)
        if data == '88':
            print('聊天结束!')
            break

if __name__=='__main__':
    # 创建套接字
    s = socket(AF_INET, SOCK_DGRAM)
    # 绑定接受数据的端口
    s.bind(('127.0.0.1', 9900))  # 绑定端口要用元组的形式
    #创建线程
    t1=Thread(target=recv_data)
    t2=Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

6.多线程实现客户端自由通信

from socket import *
from threading import Thread

def recv_data():
    while True:
        # 接收数据,返回元组
        redata = s.recvfrom(1024)
        recv_content = redata[0].decode('gbk')
        print(f"收到远程信息:{recv_content},from{redata[1]}")
        if recv_content == "88":
            print("聊天结束!")
            break

def send_data():
    # 创建接受的地址(IP地址,端口)
    addr = ('127.0.0.1', 9900)
    while True:
        # 创建发送的内容
        data = input("请输入...")
        s.sendto(data.encode('gbk'), addr)
        if data == '88':
            print('聊天结束!')
            break

if __name__=='__main__':
    # 创建套接字
    s = socket(AF_INET, SOCK_DGRAM)
    # 绑定接受数据的端口
    s.bind(('127.0.0.1', 8800))  # 绑定端口要用元组的形式
    #创建线程
    t1=Thread(target=recv_data)
    t2=Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

六、TCP编程

1.服务端简化代码

from socket import *

#创建TCP套接字
server_socket=socket(AF_INET,SOCK_STREAM)
#绑定地址和端口
server_socket.bind(('127.0.0.1',8899))  #本机监听8899端口
server_socket.listen(5) #让套接字进入监听状态,等待客户端的连接请求,5表示最大挂起的连接数
print("等待客户端连接!")
client_socket,client_info=server_socket.accept()
'''
accept() 方法会返回两个值
    client_socket是一个新创建的套接字对象,专门用于和刚刚连接到服务器的特定客户端进行通信
    当服务器通过 server_socket.listen() 进入监听状态后,一旦有客户端发起连接请求,accept() 方法就会被触发,
    并且创建一个新的套接字实例。这个新套接字与客户端建立了一对一的连接通道,之后服务器就可以通过 client_socket 使用诸如 recv() 方法来接收客户端发送的数据,使用 send() 方法向客户端发送数据 。
    假如服务器是一个客服中心,server_socket 就像是客服中心的总接待窗口,负责接收所有客户的连接请求。

    client_info是一个包含客户端地址信息的元组,这个元组包含两个元素,第一个元素是客户端的 IP 地址,第二个元素是客户端所使用的端口号

'''
recv_data=client_socket.recv(1024) #最大接受1024字节
print(f"收到信息:{recv_data.decode('gbk')},from{client_info}")
client_socket.close()  #关闭与客户端通信的套接字,释放相关资源。
server_socket.close()  #关闭服务器端的套接字,停止监听连接。

2.客户端简化代码

from socket import *

#创建TCP套接字
client_socket=socket(AF_INET,SOCK_STREAM)
#绑定地址和接口
client_socket.connect(('127.0.0.1',8899))
#发送消息
client_socket.send('hello'.encode('gbk'))
#关闭
client_socket.close()

3.服务端持续交互代码

from socket import *

#创建TCP套接字
server_socket=socket(AF_INET,SOCK_STREAM)
#绑定地址和端口
server_socket.bind(('127.0.0.1',9999))   #服务器中用bind()绑定窗口
server_socket.listen(5)  #让套接字进入监听,最多同时挂五个
print("等待客户端连接...")
client_socket,client_info=server_socket.accept()
print("客户端连接成功")
while True:
    recv_data=client_socket.recv(1024)  #最大接收1024个字节
    print(f"客户端发来信息:{recv_data.decode('gbk')},from{client_info}")
    if recv_data.decode('gbk') == 'end':
        print("会话结束!")
        break
    msg=input(">")
    client_socket.send(msg.encode('gbk'))

client_socket.close()
server_socket.close()

4.客户端持续交互代码

from socket import *

#创建TCP套接字
client_socket=socket(AF_INET,SOCK_STREAM)
#绑定地址和接口
client_socket.connect(('127.0.0.1',9999))
while True:
    client_socket.send(input(">").encode('gbk'))
    recv_data=client_socket.recv(1024)
    print(f"服务端发来信息:{recv_data.decode('gbk')}")
    if recv_data.decode('gbk')=='end':
        print("会话结束")
        break

client_socket.close()


5.多线程服务端自由通信

from socket import *
from threading import Thread

def recv_data():
    while True:
        recv_data = client_socket.recv(1024)  # 最大接收1024个字节
        recv_content=recv_data.decode('gbk')
        print(f"客户端发来信息:{recv_content},from{client_info}")
        if recv_content == 'end':
            print("会话结束!")
            break

def send_data():
    while True:
        msg = input(">")
        e_msg=msg.encode('gbk')
        client_socket.send(e_msg)
        if msg=='end':
            break

if __name__=='__main__':
    # 创建TCP套接字
    server_socket = socket(AF_INET, SOCK_STREAM)
    # 绑定地址和端口
    server_socket.bind(('127.0.0.1', 9999))  # 服务器中用bind()绑定窗口
    server_socket.listen(5)  # 让套接字进入监听,最多同时挂五个
    print("等待客户端连接...")
    client_socket, client_info = server_socket.accept()
    print("客户端连接成功")

    t1=Thread(target=recv_data)
    t2=Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    client_socket.close()
    server_socket.close()

6.多线程客户端自由通信

from socket import *
from threading import Thread

def recv_data():
    while True:
        recv_data = client_socket.recv(1024)
        recv_content=recv_data.decode('gbk')  #decode是解码,之后就变成了字符串
        print(f"服务端发来信息:{recv_content}")
        if recv_content=='end':
            break

def send_data():
    while True:
        msg=input(">")
        e_msg=msg.encode('gbk')
        client_socket.send(e_msg)
        if msg == 'end':  #只能进行字符串的比较,所以保留原始字符串,用于比较
            print("会话结束")
            break
if __name__ == '__main__':
    #创建TCP套接字
    client_socket=socket(AF_INET,SOCK_STREAM)
    #绑定地址和接口
    client_socket.connect(('127.0.0.1',9999))
    t1=Thread(target=recv_data)
    t2=Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    client_socket.close()


您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

### 关于麒麟990芯片设备安装Windows系统的兼容性和教程 #### 兼容性分析 麒麟990是一款由华为设计的ARM架构处理器,主要应用于移动终端设备(如手机和平板)。由于Windows系统的主要版本(如Windows 10和Windows 11)是以Intel x86/x64架构为主要支持目标,因此在基于ARM架构的设备上运行Windows存在一定的挑战。尽管微软推出了针对ARM架构优化的Windows 10 on ARM版本,但它并不完全支持传统的x86应用程序[^3]。 对于搭载麒麟990芯片的设备来说,其硬件架构与传统PC使用的Intel/AMD平台不同,这可能导致以下问题: - **驱动程序缺失**:Windows系统可能缺乏对麒麟990芯片及相关外设的支持,需要依赖厂商提供特定的驱动程序。 - **性能瓶颈**:即使成功安装Windows 10 on ARM,部分应用可能会通过模拟层运行,从而影响整体性能表现。 - **生态系统局限**:许多专为x86架构开发的应用无法直接运行在ARM平台上,需寻找替代解决方案或等待开发者推出原生版本[^4]。 #### 教程概述 如果决定尝试在麒麟990设备上安装Windows系统,则可以考虑以下几个方向: 1. **获取合适的镜像文件** 下载官方发布的Windows 10 on ARM ISO镜像作为基础安装包。注意确认该版本是否经过适配并适用于具体型号的硬件环境[^2]。 2. **准备启动介质** 使用工具如Rufus创建可引导U盘,将上述ISO写入其中以便后续操作过程中加载所需组件。 3. **进入BIOS设置界面调整启动顺序** 将优先级最高的选项设定为外部存储器即刚才制作完成的USB装置位置;同时关闭安全模式等相关限制功能以减少干扰因素的影响。 4. **执行实际安装流程** 按照屏幕提示逐步推进直至结束整个过程为止。期间务必留意分区规划以及必要服务的选择配置情况以免遗漏重要环节造成后期麻烦。 5. **解决潜在冲突事项** 针对可能出现的各种异常状况采取相应措施加以修复完善比如重新编译定制化的内核模块来匹配特殊需求下的图形显示效果等等[^1]。 ```bash # 示例命令用于验证当前系统架构类型 uname -a && arch ``` 需要注意的是以上方法仅作理论探讨之用,在实践当中还存在着诸多不确定性的风险要素有待克服突破才能真正实现无缝衔接的理想状态。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值