返回顶部
首页 > 资讯 > 后端开发 > Python >第十七章 Python网络编程
  • 274
分享到

第十七章 Python网络编程

十七章网络编程Python 2023-01-31 06:01:31 274人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

Socket简介在网络上的两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为一个Socket(套接字),用于描述IP地址和端口。建立网络通信连接至少要一对端口号(Socket),Socket本质是编程接口(api),对tcp/

Socket简介

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为一个Socket(套接字),用于描述IP地址和端口。

建立网络通信连接至少要一对端口号(Socket),Socket本质是编程接口(api),对tcp/IP的封装,提供了网络通信能力。

每种服务都打开一个Socket,并绑定到端口上,不同的端口对应不同的服务,就像Http对应80端口。

Socket是面向C/S(客户端/服务器)模型设计,客户端在本地随机申请一个唯一的Socket号,服务器拥有公开的socket,任何客户端都可以向它发送连接请求和信息请求。

比如:用手机打电话给10086客服,你的手机号就是客户端,10086客服是服务端。必须在知道对方电话号码前提下才能与对方通讯。

Socket数据处理流程如图:

wKiom1hFB3ihlqXzAAD9zEGLSeA858.png

17.1 socket

python中提供此服务的模块是socket和SocketServer,下面是socket常用的类、方法:

方法描述
socket.socket([family[, type[, proto]]])socket初始化函数,(地址族,socket类型,协议编号)协议编号默认0
socket.AF_INETIPV4协议通信
socket.AF_INET6IPV6协议通信
socket.SOCK_STREAMsocket类型,TCP
socket.SOCK_DGRAMsocket类型,UDP
socket.SOCK_RAW原始socket,可以处理普通socker无法处理的报文,比如ICMP
socket.SOCK_RDM更可靠的UDP类型,保证对方收到数据
socket.SOCK_SEQPACKET可靠的连续数据包服务

socket.socket()对象有以下方法:

accept()接受连接并返回(socket object, address info),address是客户端地址
bind(address)绑定socket到本地地址,address是一个双元素元组(host,port)
listen(backlog)开始接收连接,backlog是最大连接数,默认1
connect(address)连接socket到远程地址
connect_ex(address)连接socket到远程地址,成功返回0,错误返回error值
getpeername()返回远程端地址(hostaddr, port)
gettimeout()返回当前超时的值,单位秒,如果没有设置返回none
recv(buffersize[, flags])接收来自socket的数据,buffersize是接收数据量
send(data[, flags])发送数据到socket,返回值是发送的字节数
sendall(data[, flags])发送所有数据到socket,成功返回none,失败抛出异常
setblocking(flag)设置socket为阻塞(flag是true)或非阻塞(flag是flase)

温习下TCP与UDP区别:

TCP和UDP是OSI七层模型中传输层提供的协议,提供可靠端到端的传输服务。

TCP(Transmission Control Protocol,传输控制协议),面向连接协议,双方先建立可靠的连接,再发送数据。适用于可靠性要求高的应用场景。

UDP(User Data Protocol,用户数据报协议),面向非连接协议,不与对方建立连接,直接将数据包发送给对方,因此相对TCP传输速度快 。适用于可靠性要求低的应用场景。

17.1.1 TCP编程

下面创建一个服务端TCP协议的Socket演示下。

先写一个服务端:

#!/usr/bin/Python
# -*- coding: utf-8 -*-
import socket
HOST = ''                 # 为空代表所有可用的网卡
PORT = 50007              # 任意非特权端口
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)   # 最大连接数
conn, addr = s.accept()   # 返回客户端地址
print 'Connected by', addr
while 1:
    data = conn.recv(1024)   # 每次最大接收客户端发来数据1024字节
    if not data: break       # 当没有数据就退出死循环 
    print "Received: ", data # 打印接收的数据
    conn.sendall(data)       # 把接收的数据再发给客户端
conn.close()

再写一个客户端:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
HOST = '192.168.1.120'    # 远程主机IP
PORT = 50007              # 远程主机端口
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall('Hello, world') # 发送数据
data = s.recv(1024)       # 接收服务端发来的数据
s.close()
print 'Received: ', data

写好后,打开一个终端窗口执行:

# python socket-server.py
监听中...
# 直到客户端运行会接收到下面数据并退出
Connected by ('192.168.1.120', 37548)
Received:  Hello, world

再打开一个终端窗口执行:

# 如果端口监听说明服务端运行正常

# netstat -antp |grep 50007
tcp        0      0 0.0.0.0:50007           0.0.0.0:*               LISTEN      72878/python
# python socket-client.py
Received: Hello, world

通过实验了解搭到Socket服务端工作有以下几个步骤:

1)打开socket

2)绑定到一个地址和端口

3)监听进来的连接

4)接受连接

5)处理数据

17.1.2 UDP编程

服务端:

import socket
HOST = ''               
PORT = 50007             
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((HOST, PORT))
while 1:
    data, addr = s.recvfrom(1024)
    print 'Connected by', addr
    print "Received: ", data
    s.sendto("Hello %s"% repr(addr), addr)
conn.close()

客户端:

import socket
HOST = '192.168.1.99'                 
PORT = 50007             
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(data, (HOST, PORT))
data = s.recv(1024)
s.close()
print 'Received: ', data

运行方式与TCP编程一样。

使用UDP协议时,服务端就少了listen()和accept(),不需要建立连接就直接接收客户端的数据,也是把数据直接发送给客户端。

客户端少了connect(),同样直接通过sendto()给服务器发数据。

而TCP协议则前提先建立三次握手。

17.1.3 举一个更直观的socket通信例子

客户端发送bash命令,服务端接收到并执行,把返回结果回应给客户端。

服务端:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import subprocess
import socket
HOST = ''               
PORT = 50007             
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen(1)
except socket.error as e:
    s.close()
    print e
    sys.exit(1)
while 1:
    conn, addr = s.accept()
    print 'Connected by', addr
    while 1:
        # 每次读取1024字节
        data = conn.recv(1024)
        if not data: # 客户端关闭服务端会收到一个空数据
            print repr(addr) + " close."
            conn.close()
            break     
        print "Received: ", data
        cmd = subprocess.Popen(data, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        result_tuple = cmd.communicate()
        if cmd.returncode != 0 or cmd.returncode == None:
            result = result_tuple[1]
            # result = cmd.stderr.read()
        else:
            result = result_tuple[0]
            # result = cmd.stdout.read()  # 读不到标准输出,不知道为啥,所以不用
        if result:
            conn.sendall(result)
        else:
            conn.sendall("return null")
s.close()

客户端:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import socket
HOST = '192.168.1.120'   
PORT = 50007             
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
except socket.error as e:
    s.close()
    print e
    sys.exit(1)
while 1:
    cmd = raw_input("Please input command: ")
    if not cmd: continue
    s.sendall(cmd)
    recv_data = s.recv(1024)
    print 'Received: ', recv_data
s.close()

查看运行效果,先运行服务端,再运行客户端:

# python socket-server.py
Connected by ('192.168.1.120', 45620)
Received:  ls
Received:  touch a.txt
Received:  ls

# python socket-client.py
Please input command: ls
Received: 
socket-client.py
socket-server.py
Please input command: touch a.txt
Received:  return null
Please input command: ls
Received: 
a.txt
socket-client.py
socket-server.py
Please input command:

我想通过上面这个例子你已经大致掌握了socket的通信过程。

再举一个例子,通过socket获取本机网卡IP:

>>> socket.gethostname()
'ubuntu'
>>> socket.gethostbyname(socket.gethostname())
'127.0.1.1'
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.connect(('10.255.255.255', 0))
>>> s.getsockname()
('192.168.1.120', 35765)
>>> s.getsockname()[0]
'192.168.1.120'


博客地址:http://lizhenliang.blog.51cto.com

QQ群:323779636(Shell/Python运维开发群)


17.2 SocketServer

ScoketServer是Socket服务端库,比socket库更高级,实现了多线程和多线程并发处理多个客户端请求。

下面是几个常用的类:

SocketServer.TCPServer(server_address

RequestHandlerClassbind_and_activate=True)

服务器类,TCP协议

SocketServer.UDPServer(server_address

RequestHandlerClassbind_and_activate=True)

服务器类,UDP协议

SocketServer.BaseServer(server_address

RequestHandlerClass)

这个是所有服务器对象的超类。它定义了接口,不提供大多数方法,在子类中进行。
SocketServer.BaseRequestHandler这个是所有请求处理对象的超类。它定义了接口,一个具体的请求处理程序子类必须定义一个新的handle()方法。
SocketServer.StreamRequestHandler流式socket,根据socket生成读写socket用的两个文件对象,调用rfile和wfile读写
SocketServer.DatagramRequestHandler数据报socket,同样生成rfile和wfile,但UDP不直接关联socket。这里rfile是由UDP中读取的数据生成,wfile则是新建一个StringIO,用于写数据
SocketServer.ForkingMixIn/ThreadingMixIn多进程(分叉)/多线程实现异步。混合类,这个类不会直接实例化。用于实现处理多连接

SocketServer.BaseServer()对象有以下方法:

fileno()返回一个整数文件描述符上服务器监听的套接字
handle_request()处理一个请求
serve_forever(poll_interval=0.5)处理,直至有明确要求shutdown()的请求。轮训关机每poll_interval秒
shutdown()告诉serve_forever()循环停止并等待
server_close()清理服务器
address_family地址族
server_address监听的地址
RequestHandlerClass用户提供的请求处理类
socketsocket对象上的服务器将监听传入的请求
allow_reuse_address服务器是否允许地址的重用。默认False
request_queue_size请求队列的大小。
socket_typesocket类型。socket.SOCK_STREAM或socket.SOCK_DGRAM
timeout超时时间,以秒为单位
finish_request()实际处理通过实例请求RequestHandleClass并调用其handle()方法
get_request()必须接受从socket的请求,并返回
handle_error(request, client_address)如果这个函数被条用handle()
process_request(request, client_address)?
server_activate()?
server_bind()由服务器构造函数调用的套接字绑定到所需的地址
verify_request(request, client_address)返回一个布尔值,如果该值是True,则该请求将被处理,如果是False,该请求将被拒绝。

创建一个服务器需要几个步骤:

1)创建类,继承请求处理类(BaseRequestHandler),并重载其handle()方法,此方法将处理传入的请求

2)实例化服务器类之一,它传递服务器的地址和请求处理程序类

3)调用handle_request()或serve_forever()服务器对象的方法来处理一个或多个请求

4)调用server_close()关闭套接字

17.2.1 TCP编程

服务端:

#!/usr/bin/python
# -*- coding: utf-8 -*
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    请求处理程序类。
    每个连接到服务器都要实例化一次,而且必须覆盖handle()方法来实现与客户端通信
    """
    def handle(self):
        # self.request 接收客户端数据
        self.data = self.request.recv(1024).strip()
        print "%s wrote:" % (self.client_address[0])
        print self.data
        # 把接收的数据转为大写发给客户端
        self.request.sendall(self.data.upper())
if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    # 创建服务器并绑定本地地址和端口
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
    # 激活服务器,会一直运行,直到Ctrl-C中断
    server.serve_forever()

另一个请求处理程序类,利用流(类文件对象简化通信提供标准文件接口):

class MyTCPHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        # self.rfile创建的是一个类文件对象处理程序,就可以调用readline()而不是recv()
        self.data = self.rfile.readline().strip()
        print "%s wrote:" % (self.client_address[0])
        print self.data
        # 同样,self.wfile是一个类文件对象,用于回复客户端
        self.wfile.write(self.data.upper())

客户端:

import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    sock.connect((HOST, PORT))
    sock.sendall(data + "\n")
    received = sock.recv(1024)
finally:
    sock.close()
print "Sent: %s" % data
print "Received: %s" % received

服务端结果:

# python TCPServer.py
127.0.0.1 wrote:
hello
127.0.0.1 wrote:
nice

客户端结果:

# python TCPClient.py hello
Sent: hello
Received: HELLO
# python TCPClient.py nice
Sent: nice
Received: NICE

17.2.2 UDP编程

服务端:

import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.data = self.request[0].strip()
        self.socket = self.request[1]
        print "%s wrote:" % (self.client_address[0])
        print self.data
        self.socket.sendto(self.data.upper(), self.client_address)
if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = SocketServer.UDPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

客户端:

import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(data + "\n", (HOST, PORT))
received = sock.recv(1024)
print "Sent: %s" % data
print "Received: %s" % received

与TCP执行结果一样。

17.2.3 异步混合

创建异步处理,使用ThreadingMixIn和ForkingMixIn类。

ThreadingMixIn类的一个例子:

#!/usr/bin/python
# -*- coding: utf-8 -*
import socket
import threading
import SocketServer
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.current_thread()
        response = "%s: %s" % (cur_thread.name, data)
        self.request.sendall(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass
def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print "Received: %s" % response
    finally:
        sock.close()
if __name__ == "__main__":
    # 端口0意味着随机使用一个未使用的端口
    HOST, PORT = "localhost", 0
    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address
    # 服务器启动一个线程,该线程将开始。每个线程处理每个请求
    server_thread = threading.Thread(target=server.serve_forever)
    # 作为守护线程
    server_thread.daemon = True
    server_thread.start()
    print "Server loop running in thread:", server_thread.name
    client(ip, port, "Hello World 1")
    client(ip, port, "Hello World 2")
    client(ip, port, "Hello World 3")
    server.shutdown()
      server.server_close()

# python socket-server.py
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3


--结束END--

本文标题: 第十七章 Python网络编程

本文链接: https://lsjlt.com/news/189604.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 第十七章 Python网络编程
    Socket简介在网络上的两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为一个Socket(套接字),用于描述IP地址和端口。建立网络通信连接至少要一对端口号(Socket),Socket本质是编程接口(API),对TCP/...
    99+
    2023-01-31
    十七章 网络编程 Python
  • MySQL必知必会--第十六章~第十七章
    使用带聚集函数的联结     select customers.cust_name, customers.cust_id, count(orders.order_num) as num_id from customers  inn...
    99+
    2016-07-26
    MySQL必知必会--第十六章~第十七章
  • 《JavaSE-第十七章》之LinkedList
    前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页:KC老衲爱尼姑的博客主页 博主的github,平常所写代码皆在于此 刷题求职神器 共勉:ta...
    99+
    2023-09-07
    java 数据结构 开发语言
  • 第十三章 Python数据库编程
    本章节讲解Python操作数据库,完成简单的增删改查工作,以MySQL数据库为例。Python的MySQL数据库操作模块叫MySQLdb,需要额外的安装下。通过pip工具安装:pip install MyS...
    99+
    2024-04-02
  • python核心编程2 第十章 练习
    10-6.改进的open()。为内建的open()函数创建一个封装。使得成功打开文件后,返回文件句柄:若打开失败则返回给调用者None, 而不是生成一个异常。这样你打开文件就不需要额外的异常处理语句。 1 def openfile(f...
    99+
    2023-01-30
    第十章 核心 python
  • python核心编程2 第十二章 练习
    12–5. 使用 __import__().(a) 使用 __import__ 把一个模块导入到你的名称空间。 你最后使用了什么样的语法 (b) 和上边相同, 使用 __import__() 从指定模块导入特定的名字。 1 module...
    99+
    2023-01-30
    十二章 核心 python
  • 第二十七天- 网络通信协议 TCP UD
        1.网络通信协议   osi七层模型:按照分工不同把互联网协议从逻辑上划分了层级       socket层   2.理解socket:   Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计...
    99+
    2023-01-30
    通信协议 十七天 网络
  • Python 第十二章 virtuale
    virtualenv在开发Python应用程序的时候,系统安装的Python3只有一个版本3.4,所有第三方包都会被pip安装到python3的site-packages目录下。如果我们同时开发多个Python程序,那么这些应用程序会公用一...
    99+
    2023-01-31
    十二章 Python virtuale
  • 第七章 Python异常处理
    什么是异常?顾名思义,异常就是程序因为某种原因无法正常工作了,比如缩进错误、缺少软件包、环境错误、连接超时等等都会引发异常。一个健壮的程序应该把所能预知的异常都应做相应的处理,应对一些简单的异常情况,使得更好的保证程序长时间运行。即使出了问...
    99+
    2023-01-31
    第七章 异常 Python
  • Netty | 第1章 Java NIO 网络编程《Netty In Action》
    目录前言1. Java 网络编程1.1 Javs NIO 基本介绍1.2 缓冲区 Buffer1.2 通道 Channel1.3 选择器 Selector1.4 NIO 非阻塞网络编程原理分析2. 线程模型概述2.1 传统阻塞 IO 服务...
    99+
    2015-03-26
    Netty | 第1章 Java NIO 网络编程《Netty In Action》
  • 『赠书活动 | 第十七期』《Python网络爬虫:从入门到实战》
    💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! 『赠书活动 | 第十七期』 本...
    99+
    2023-09-02
    python 爬虫 开发语言
  • 第十五章 Python多进程与多线程
    15.1 multiprocessingmultiprocessing是多进程模块,多进程提供了任务并发性,能充分利用多核处理器。避免了GIL(全局解释锁)对资源的影响。有以下常用类:类描述Process(group=None, targe...
    99+
    2023-01-31
    十五章 多线程 进程
  • 《python核心教程2》第十章 练习
    10-6.改进的open()。为内建的open()函数创建一个封装。使得成功打开文件后,返回文件句柄:若打开失败则返回给调用者None, 而不是生成一个异常。这样你打开文件就不需要额外的异常处理语句。 1 def openfile(f...
    99+
    2023-01-30
    第十章 核心 教程
  • python学习笔记(十 三)、网络编程
    最近心情有点儿浮躁,难以静下心来     Python提供了强大的网络编程支持,很多库实现了常见的网络协议以及基于这些协议的抽象层,让你能够专注于程序的逻辑,而无需关心通过线路来传输比特的问题。 1 几个网络模块   1.1 模块sock...
    99+
    2023-01-31
    学习笔记 网络编程 python
  • python核心编程(第三版)网络编程错
    //服务器端代码from socket import * from time import ctime host='localhost' port=3330 bufsize = 1024 addr = (host,port) tcp...
    99+
    2023-01-30
    第三版 网络编程 核心
  • 《Python核心编程》第五章
    5-1.整型。讲讲Python普通整型和长整型的区别?   答案:    在大多数32位机器上,标准整型的取值范围是-2^31~2^31-1,如果在64位机器上使用64位编译器编译的Python,则整型是64位的。而长整型能表示的数值仅仅与...
    99+
    2023-01-31
    第五章 核心 Python
  • 第十二章 Python文件操作
    12.1 open()open()函数作用是打开文件,返回一个文件对象。用法格式:open(name[, mode[, buffering[,encoding]]]) -> file objectname 文件名mode 模式,比如以...
    99+
    2023-01-31
    十二章 操作 文件
  • 【android编程】第七讲-android Activity
    【android编程】第七讲-android Activity 文章目录【android编程】第七讲-android Activity1. 学习...
    99+
    2022-06-06
    activity Android
  • Python 网络编程
    Python 网络编程 Python 提供了两个级别访问的网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统 Socket 接口的全部方法。 高级别的网络服务模块 S...
    99+
    2023-08-31
    网络 服务器 运维
  • Python网络编程
    # notes 要点网络编程 客户端/服务器架构 客户端/服务器网络编程 套接字是计算机网络数据结构。在任何类型的通信开始之前,网络应用程序必须创建套接字。可以将它们比作电话插孔,没有它将无法进行通信。 进程间通信(Inter Proc...
    99+
    2023-01-31
    网络编程 Python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作