基于python socket实现TCP/UDP通信

这篇具有很好参考价值的文章主要介绍了基于python socket实现TCP/UDP通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

两个应用程序如果需要进行通讯最基本的一个前提就是能够唯一的标示一个进程,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,本文将对socket进行介绍。

什么是socket

什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用来实现进程在网络中通信。

学习网络编程的目的是为了开发基于互联网通信的软件,不论是BS架构的还是CS架构的。我们开发互联网通信软件是处于TCP/IP五层协议中的应用层,当涉及到数据需要经过互联网传输时,就需要使用到socket抽象层。这个socket抽象层不属于TCP/IP五层,是一个抽象的出来的,帮我们封装了包括传输层以下的其他各层。它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。在开发时,只需要遵循socket的规定编写代码,写出来的程序自然遵循TCP/UDP协议。

套接字发展历史及分类

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

基于文件类型的套接字家族

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

基于网络类型的套接字家族

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

socket模块

socket可以实现两个网络中的进程进行通信,我们可以从日常生活中的例子来对比socket的工作流程,比如你要给一个朋友打电话,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了socket的工作原理。

服务端:

​ 1 初始化socket对象

​ 2 socket对象与服务端的IP和端口绑定(bind)

​ 3 对端口进行监听(listen)

客户端:

​ 1 初始化socket对象

​ 2 连接服务器(connect)

​ 3 如果连接成功,客户端与服务端的连接就建立了

连接成功后:

​ 1 客户端发送数据请求

​ 2 服务端接收请求并处理请求

​ 3 讲回应数据发送给客户端,客户端读取数据

​ 4 关闭连接,一次交互结束

python中的socket模块就封装了socket抽象层,并提供了一些简单的接口帮助我们实现上述过程。下述代码介绍socket模块的基本使用:

补充:python查看源码的方式:按住ctrl,将鼠标悬停在需要查看源码的对象上,点击,就可以看见源码。

# socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。socket_family默认是-1,表示AF_INET,socket_type默认也是-1,表示SOCK_STREAM。可以通过源码查看
socket.socket(socket_family, socket_type, protocal=0)

# 获取tcp/ip套接字
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_sock = socket.socket()  # 默认就是-1,可以不写

# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

socket模块为客户端程序和服务端程序分别提供了不同的方法进行收发数据,也提供了一些公用的方法。知道了socket模块的用法,我们就可以根据socket模块基于TCP/UDP协议进行开发客户端和服务端的小程序了。我们依次来进行介绍:

首先是socket模块为服务端(sever)提供的方法:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 获取socket对象
s.bind()   # 绑定主机、端口号到套接字
s.listen()  # 开始TCP监听
s.accept()  # 被动接受TCP客户的连接,(阻塞式)等待连接的到来

下面来看socket模块为客户端(client)提供的方法:

import socket

s = socket.socket()  # socket对象
s.connect()  # 主动初始化连接TCP服务器
s.connect_ex()  # connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

最后就是一些socket为客户端和服务端提供的一些公共方法:

s.recv()   # 接收TCP数据
s.send()   # 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall()   # 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom()   # 接收UDP数据
s.sendto()   # 发送UDP数据
s.getpeername()   # 连接到当前套接字的远端的地址
s.getsockname()   # 当前套接字的地址
s.getsockopt()   # 返回指定套接字的参数
s.setsockopt()   # 设置指定套接字的参数
s.close()   # 关闭套接字连接

基于TCP的套接字

tcp协议的基于双向连接的,因此必须先启动服务端,然后再启动客户端连接服务器。

先从服务器端说起:服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。

在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。

客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

以上就是一次基于TCP通信的简单流程,根据打电话的原理对比,具体代码如下:

简单版TCP通信

服务端文件:

# sever.py  服务端文件
# 以手机接打电话为例
import socket

# 1 买手机---获取服务端收发数据的对象
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 2 手机插卡---给服务端绑定IP+端口
phone.bind(('127.0.0.1',6666))

# 3 开机---服务端处于监听状态
phone.listen(3)  # 半连接池只能存放三个待确认的连接请求

# 4 等待来电---服务端与客户端建立连接,建立连接后可以拿到TCP连接的通道信息,和客户端的IP和接口
conn,client_addr = phone.accept()
print(conn)
print('客户端IP和接口',client_addr)

# 5 电话接通,两人愉快的聊天---收发数据
data = conn.recv(1024)  # 最大接收数据量为1024bytes
print('客户端消息', data.decode('utf-8'))
conn.send(data.upper())

# 6 挂断电话---断开与客户端的连接
conn.close()

# 7 手机关机---服务端关机
phone.close()

客户端文件

# client.py
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

phone.connect(('127.0.0.1',6666))

phone.send('show 信息'.encode('utf-8'))

data = phone.recv(1024)

print('服务端',data.decode('utf-8'))

phone.close()

TCP循环通信

上述简单版的通信代码,有一个问题,就是费了好大劲才连接成功,结果发一句消息连接就断开了,就像打电话,打一次说一句话,挂断电话,如果还有没说完的,还需要再打....

为了解决上述问题,我们可以使用循环来不断接收或者发送数据 - 循环通讯

服务端文件:

# sever.py
import socket

# 1 买手机---获得服务端的对象
phone = socket.socket()

# 2 手机插卡---确定服务端的IP和端口
phone.bind(('127.0.0.1',7890))

# 3 手机开机---服务端进入监听状态
phone.listen(3)

# 4 等待接听电话,获取TCP通道和客户端的IP和端口

conn,client_addr = phone.accept()

# 5 通电话---收发数据
while True:
    # 异常处理:当防止客户端突然关闭服务端崩溃
    try:
        data = conn.recv(1024)
        if not data:break
        print('客户端',data.decode('utf-8'))

        conn.send(data.upper())
    except Exception:
        break

# 6 挂断电话---服务端与客户端通道断开
conn.close()

# 7 关机---服务端关机
phone.close()

客户端文件:

# client.py
import socket

phone = socket.socket()
phone.connect(('127.0.0.1', 7890))
while True:
    info = input('>>').strip()
    # 当发送的数据长度为0时,服务端和客户端都会进入等待收数据的阻塞阶段,所以进行判断,判断用户输入的信息被strip处理后,长度是否为0
    if len(info) == 0:continue
    if info == 'q': break
    phone.send(info.encode('utf-8'))
    data = phone.recv(1024)
    print('服务端', data.decode('utf-8'))

phone.close()

服务端不关闭的TCP通信

上述代码方案也存在问题,作为服务端应该满足两个条件,一是需要为客户端一直提供服务,二是并发的提供服务,上述循环通信当客户端断开连接后,服务端也随之终止运行,就无法再向其他客户端提供服务了。因此我们可以让服务端一直处于不关闭的状态。下述为优化后的服务端代码:

# sever.py
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

phone.bind(('127.0.0.1',65447))

phone.listen(5)
while True:
    conn, client_addr = phone.accept()
    while True:
        try:
            data = conn.recv(1024)
            if not data:break
            print('客户端',data.decode('utf-8'))
            conn.send(data.upper())
        except Exception:
            break

    conn.close()  # 这里只是断开客户端和服务端的连接

当然,上述代码也是存在需要优化的地方,就是服务端只能同时为一个客户端进行服务,如果想要让服务端为多个服务端进行服务,需要用到我们后面将要学的知识 - 并发编程。这里就不做过多介绍了。

在使用TCP通信时,客户端如果发的消息的空,也会出现问题。如果客户端发的消息为空,这个消息其实是不会发出去的,只是应用程序将这个消息发给了操作系统,操作系统收到后,发现是空,不会往外发的。所以客户端发空后进入recv等状态状态,而此时服务端是压根没有收到任何消息也不会回复,所以就陷入的尴尬的两边等状态。解决的办法就是判断客户端发的消息是否为空,为空直接跳到下一个循环,不让这个空消息发给操作系统。

基于UDP的套接字

udp是无链接的,先启动哪一端都不会报错。因此,它要比基于tcp的套接字在使用上简单很多。

UDP协议是数据报协议,发空的时候也会自带报头,因此客户端输入空,服务端也能收到。

基于udp的套接字是没有连接的,客户端和服务端都可以先开启套接字通信,也都可以提前结束通信,即客户端离开不会影响到服务端的正常运行。

服务端代码

# server.py
import socket

ip_port = ('127.0.0.1', 8080)
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(ip_port)
print('服务端开始监听......')

while True:
    get_msg, client_addr = server.recvfrom(1024)
    print('from client:', get_msg)
    server.sendto(get_msg.upper(), client_addr)

# server.close()

客户端代码文章来源地址https://www.toymoban.com/news/detail-563069.html

import socket

ip_port = ('127.0.0.1', 8080)
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while 1:
    msg = input('>>>:').strip()
    if msg == 'q':
        break
    if not msg:		# 其实,udp的套接字,支持客户端发空的,服务端也能收到空
        continue
    client.sendto(msg.encode('utf-8'), ip_port)
    get_msg, server_addr = client.recvfrom(1024)
    print(get_msg.decode('utf-8'))                     # 关闭客户套接字

到了这里,关于基于python socket实现TCP/UDP通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python3套接字编程之socket和socketserver(TCP和UDP通信)

    socket和socketserver是python3中socket通信模块,关于其使用做如下总结。 目录 1.socket 1.1模块引入 1.2套接字获取 1.3套接字接口 1.3.1 服务端 1.3.2 客户端套接字函数 1.3.3 公共套接字函数 1.3.4 面向锁的套接字方法 1.3.5 面向文件的套接字的函数 2.socketserver 3.TCP 3.1 socket类型TCP 3.2 sockets

    2024年02月15日
    浏览(75)
  • 网络通信(Socket/TCP/UDP)

    Socket(又叫套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接协议,客户端的IP地址,客户端的端口,服务器的IP地址,服务器的端口。 一个Socket是一对IP地址和端口。 Socket可以看

    2024年01月22日
    浏览(55)
  • Python使用 Twisted 实现 TCP/UDP Socket 编程

    更多文章: 技数未来 环境准备: - 安装Python:确保你已经安装了Python解释器。 - 安装Twisted:可以通过pip命令来安装Twisted库,运行`pip install twisted`即可。 依赖的类库: - twisted.internet.protocol:包含了实现TCP/UDP Socket编程所需的协议类。 - twisted.internet.reactor:用于处理事件循环

    2024年02月16日
    浏览(49)
  • 【Java】网络编程与Socket套接字、UDP编程和TCP编程实现客户端和服务端通信

    为什么需要网络编程? 现在网络普及程序越来越高,网络上保存着我们日常生活中需要的各种资源,使用程序通过网络来获取这些资源的过程就需要网络编程来实现。 什么是网络编程? 网络编程,指网络上的主机,通过不同的进程以程序的方式实现网络通信(网络数据传输)

    2024年02月17日
    浏览(79)
  • 基于UDP/TCP的网络通信编程实现

    红色是心中永不褪色的赤诚 操作系统为网络编程提供了 Socket api , Socket是基于TCP/IP协议的网络通信的基本单元, 基于Socket的网络程序开发就是 网络编程. 由于直接与应用层联系的是传输层, 所以针对应用层协议(TCP, UDP), Shocket提供了三种套接字, 分别是 流套接字(使用TCP) , 数据报

    2024年02月08日
    浏览(54)
  • Linux TCP/UDP socket 通信和IO多路复用

    主机字节序 16 位值 == 网络字节序 16 位值 主机字节序 32 位值 == 网络字节序 32 位值 主机字节序的字符串IP地址  == 网络字节序的整形IP地址 将监听的套接字和本地IP和端口进行关联 给监听的套接字设置监听,开始检测客户端链接 等待并接受客户端的连接,阻塞函数,没有客

    2024年02月05日
    浏览(61)
  • tcp/udp socket 网络通信中超时时间的设置

    1.connect函数的超时时间设置只对TCP有效 UDP由于是无连接的connect都会返回success 有两种方法: 第一种方法 默认的socket是阻塞模式 我们只需要设置其为非阻塞模式,然后调用select去查询其状态 代码如下:  第二种是 默认其为阻塞模式  通过setsockopt 函数设置TCP_SYNCNT 值 头文件

    2024年02月15日
    浏览(41)
  • 【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

    ​ 哈喽,大家好~我是你们的老朋友: 保护小周ღ   本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信 ,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~ 本期收录于博主的专栏 : JavaEE_保

    2024年02月02日
    浏览(70)
  • 基于TCP/UDP的Socket编程

    ---- socket概述: socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。 socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种\\\"打开—读/写—关闭\\\"模式的实现,服务器和客户端各自维护一个

    2024年02月10日
    浏览(39)
  • 【socket】从计算机网络基础到socket编程——Windows && Linux C语言 + Python实现(TCP+UDP)

    简单讲一下基础知识,便于后面代码的理解,建议大概浏览一下这一小节内容。这里讲的只是冰山一角,建议大家学习计算机网络相关知识,推荐几本书: 《计算机网络》(谢希仁) 《计算机网络 自顶向下方法》 《计算机网络技术》 《计算机网络基础及应用》 《Linux C从入

    2024年02月08日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包