python socket和socketserver

简介: python socket和socketserver

Python提供了两个基本的socket模块。一个是socket,它提供了标准的BSD Socket API;另一个是socketServer,它提供了服务器中心类,可以简化网络服务器的开发。

       下面先简要介绍socket模块包含的类及其使用。

       1.开始了解socket模块前,先熟悉下Python的网络编程模块主要支持的两种Intent协议:TCP和UDP。TCP协议是一种面向连接的可靠协议,用于建立机器之间的双向通信流。UDP协议是一种较低级别的、以数据包为基础的协议(无连接传输模式)。与TCP不同,UDP信息不可靠。

 2.socket模块的部分类方法介绍

类方法

说明

socket.socket(family, type[,proto])

创建并返回一个新的 socket对象

socket.getfqdn(name)

将使用点号分隔的 IP地址字符串转换成一个完整的域名

socket.gethostbyname(hostname)

将主机名解析为一个使用点号分隔的 IP地址字符串

socket.gethostbyname_ex(name)

它返回一个包含三个元素的元组,从左到右分别是给定地址的主要的主机名、同一IP地址的可选的主机名的一个列表、关于同一主机的同一接口的其它IP地址的一个列表(列表可能都是空的)。

socket.gethostbyaddr(address)

作用与gethostbyname_ex相同,只是你提供给它的参数是一个IP地址字符串

Socket.getservbyname(service,protocol)

它要求一个服务名(如'telnet'或'ftp')和一个协议(如'tcp'或'udp'),返回服务所使用的端口号

socket.fromfd(fd, family, type)

从现有的文件描述符创建一个 socket对象

 

3.socket对象的部分方法介绍

实例方法

说明

sock.bind( (adrs, port) )

将 socket绑定到一个地址和端口上

sock.accept()

返回一个客户机 socket(带有客户机端的地址信息)

sock.listen(backlog)

将 socket设置成监听模式,能够监听 backlog 外来的连接请求

sock.connect( (adrs, port) )

将 socket连接到定义的主机和端口上

sock.recv( buflen[, flags] )

从 socket中接收数据,最多 buflen 个字符

sock.recvfrom( buflen[, flags] )

从 socket中接收数据,最多 buflen 个字符,同时返回数据来源的远程主机和端口号

sock.send( data[, flags] )

通过 socket发送数据

sock.sendto( data[, flags], addr )

通过 socket发送数据

sock.close()

关闭 socket

sock.getsockopt( lvl, optname )

获得指定 socket 选项的值

sock.setsockopt( lvl, optname, val )

设置指定 socket选项的值

 

4.编写socket测试程序

(a)编写server的步骤

第一步是创建socket对象。调用socket构造函数。如:

socket = socket.socket( family, type )

family参数代表地址家族,可为AF_INET或AF_UNIX。AF_INET家族包括Internet地址,AF_UNIX家族用于同一台机器上的进程间通信。

type参数代表套接字类型,可为SOCK_STREAM(流套接字)和SOCK_DGRAM(数据报套接字)。

第二步是将socket绑定到指定地址。这是通过socket对象的bind方法来实现的:

socket.bind( address )

由AF_INET所创建的套接字,address地址必须是一个双元素元组,格式是(host,port)。host代表主机,port代表端口号。如果端口号正在使用、主机名不正确或端口已被保留,bind方法将引发socket.error异常。

第三步是使用socket套接字的listen方法接收连接请求。

socket.listen( backlog )

backlog指定最多允许多少个客户连接到服务器。它的值至少为1。收到连接请求后,这些请求需要排队,如果队列满,就拒绝请求。

第四步是服务器套接字通过socket的accept方法等待客户请求一个连接。

connection, address = socket.accept()

调 用accept方法时,socket会时入“waiting”状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有两个元素的元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素 address是客户的Internet地址。

第 五步是处理阶段,服务器和客户端通过send和recv方法通信(传输 数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接收信息。调用recv 时,服务器必须指定一个整数,它对应于可通过本次方法调用来接收的最大数据量。recv方法在接收数据时会进入“blocked”状态,最后返回一个字符 串,用它表示收到的数据。如果发送的数据量超过了recv所允许的,数据会被截短。多余的数据将缓冲于接收端。以后调用recv时,多余的数据会从缓冲区 删除(以及自上次调用recv以来,客户可能发送的其它任何数据)。

传输结束,服务器调用socket的close方法关闭连接。

(b)编写client的步骤

首先创建一个socket以连接服务器:socket =socket.socket( family, type )

使用socket的connect方法连接服务器。对于AF_INET家族,连接格式如下:

socket.connect( (host,port) )

host代表服务器主机名或IP,port代表服务器进程所绑定的端口号。如连接成功,客户就可通过套接字与服务器通信,如果连接失败,会引发socket.error异常。

处理阶段,客户和服务器将通过send方法和recv方法通信。

Server:

import socket
port=8081
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#从指定的端口,从任何发送者,接收UDP数据
s.bind(('',port))
print('正在等待接入...')
while True:
    #接收一个数据
    data,addr=s.recvfrom(1024)
    print('Received:',data,'from',addr)

Client:

import socket

port=8081

host='localhost'

s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

s.sendto(b'hello,this is a test info !',(host,port))

很简单 。下面是TCP方式:

Server:

#-*- coding: utf-8 -*-
from socket import *
from time import ctime
HOST=''
PORT=12345
BUFSIZ=1024
ADDR=(HOST, PORT)
sock=socket(AF_INET, SOCK_STREAM)
sock.bind(ADDR)
sock.listen(5)
while True:
    print('waiting for connection')
    tcpClientSock, addr=sock.accept()
    print('connect from ', addr)
    while True:
        try:
            data=tcpClientSock.recv(BUFSIZ)
        except:
            print(e)
            tcpClientSock.close()
            break
        if not data:
            break
        s='Hi,you send me :[%s] %s' %(ctime(), data.decode('utf8'))
        tcpClientSock.send(s.encode('utf8'))
        print([ctime()], ':', data.decode('utf8'))
tcpClientSock.close()
sock.close()

Client:

#-*- coding: utf-8 -*-
from socket import *
class TcpClient:
    HOST='127.0.0.1'
    PORT=12345
    BUFSIZ=1024
    ADDR=(HOST, PORT)
    def __init__(self):
        self.client=socket(AF_INET, SOCK_STREAM)
        self.client.connect(self.ADDR)
        while True:
            data=input('>')
            if not data:
                break
            self.client.send(data.encode('utf8'))
            data=self.client.recv(self.BUFSIZ)
            if not data:
                break
            print(data.decode('utf8'))
            
if __name__ == '__main__':
    client=TcpClient()

上面的TCP方式有个问题,不能退出,好吧,我们改造一下,使这个程序可以发送quit命令以退出:

Server:

#-*- coding: utf-8 -*-
from socket import *
from time import ctime
from time import localtime
import time
HOST=''
PORT=1122  #设置侦听端口
BUFSIZ=1024
ADDR=(HOST, PORT)
sock=socket(AF_INET, SOCK_STREAM)
sock.bind(ADDR)
sock.listen(5)
#设置退出条件
STOP_CHAT=False
while not STOP_CHAT:
    print('等待接入,侦听端口:%d' % (PORT))
    tcpClientSock, addr=sock.accept()
    print('接受连接,客户端地址:',addr)
    while True:
        try:
            data=tcpClientSock.recv(BUFSIZ)
        except:
            #print(e)
            tcpClientSock.close()
            break
        if not data:
            break
        #python3使用bytes,所以要进行编码
        #s='%s发送给我的信息是:[%s] %s' %(addr[0],ctime(), data.decode('utf8'))
        #对日期进行一下格式化
        ISOTIMEFORMAT='%Y-%m-%d %X'
        stime=time.strftime(ISOTIMEFORMAT, localtime())
        s='%s发送给我的信息是:%s' %(addr[0],data.decode('utf8'))
        tcpClientSock.send(s.encode('utf8'))
        print([stime], ':', data.decode('utf8'))
        #如果输入quit(忽略大小写),则程序退出
        STOP_CHAT=(data.decode('utf8').upper()=="QUIT")
        if STOP_CHAT:
            break
tcpClientSock.close()
sock.close()

Client:

#-*- coding: utf-8 -*-
from socket import *
class TcpClient:
    #测试,连接本机
    HOST='127.0.0.1'
    #设置侦听端口
    PORT=1122 
    BUFSIZ=1024
    ADDR=(HOST, PORT)
    def __init__(self):
        self.client=socket(AF_INET, SOCK_STREAM)
        self.client.connect(self.ADDR)
        while True:
            data=input('>')
            if not data:
                break
            #python3传递的是bytes,所以要编码
            self.client.send(data.encode('utf8'))
            print('发送信息到%s:%s' %(self.HOST,data))
            if data.upper()=="QUIT":
                break            
            data=self.client.recv(self.BUFSIZ)
            if not data:
                break
            print('从%s收到信息:%s' %(self.HOST,data.decode('utf8')))
            
            
if __name__ == '__main__':
    client=TcpClient()

下面先简要介绍socketserver模块包含的类及其使用

SocketServer是标准库中一个高级别的模块。用于简化网络客户与服务器的实现。模块中,已经实现了一些可供使用的类。

我们将再次实现之前的那个基本TCP的例子。你会注意到新实现与之前有很多相似之处,但你也要注意到,现在很多繁杂的事情已经被封装好了,你不用再去关心那个样板代码了。例子给出的是一个最简单的同步服务器。

为了要隐藏实现的细节。我们现在写程序时会使用类,这是与之前代码的另一个不同。用面向对象的方法可以帮助我们更好的组织数据与逻辑功能。你也会注意到,我们的程序现在是“事件驱动”了。这就意味着,只有在事件出现的时候,程序才有“反应”。

在之前的服务循环中,我们阻塞等待请求,有请求来的时候就处理请求,然后再回去继续等待。现在的服务循环中,就不用在服务器里写代码了,改成定义一个处理器,服务器在收到进来的请求的时候,可以调用你的处理函数。

1. 创建一个SocketServerTCP服务器:

在代码中,先导入我们的服务器类,然后像之前一样定义主机常量。主机常量后就是我们的请求处理器类,然后是启动代码。在下面的代码片断中可以看到更多细节。

#!/usr/bin/env python
 
from SocketServer import (TCPServer as TCP,
                          StreamRequestHandler as SRH)
from time import ctime
 
HOST = ''
PORT = 12346
ADDR = (HOST, PORT)
 
class MyRequestHandler(SRH):
    def handle(self):
        print '...connected from:', self.client_address
        self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline()))
 
tcpServ = TCP(ADDR, MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()

我们从SocketServer的StreamRequestHandler类中派生出一个子类,并重写handle()函数。在BaseRequest类中,这个函数什么也不做。在有客户消息进来的时候,handle()函数就会被调用。StreamRequestHandler 类支持像操作文件对象那样操作输入输出套接字。我们可以用readline()函数得到客户消息,用write()函数把字符串发给客户。

为了保持一致性,我们要在客户与服务器两端的代码里都加上回车与换行。实际上,你在代码中看不到这个,因为,我们重用了客户传过来的回车与换行。

2. 创建SocketServerTCP客户端

#!/usr/bin/env python
 
from socket import *
 
HOST = 'localhost'
PORT = 12346
BUFSIZE = 1024
ADDR = (HOST, PORT)
 
while True:
    tcpCliSock = socket(AF_INET, SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    data = raw_input('>')
    if not data:
        break
    tcpCliSock.send('%s\r\n' % data)
    data = tcpCliSock.recv(BUFSIZE)
    if not data:
        break
    print data.strip()
    tcpCliSock.close()

SocketServer的请求处理器的默认行为是接受连接,得到请求,然后就关闭连接。这使得我们不能在程序的运行时,一直保持连接状态,要每次发送数据到服务器的时候都要创建一个新的套接字。这种行为使得TCP 服务器的行为有些像UDP服务器。不过,这种行为也可以通过重写请求处理器中相应的函数来改变。

现在,我们的客户端有点完全不一样了(我们得每次都创建一个连接)。其它的小区别在服务器代码的逐行解释中已经看到了:我们使用的处理器类像文件一样操作套接字,所以我们每次都要发送行结束字符(回车与换行)。服务器只是保留并重用我们发送的行结束字符。当我们从服务器得到数据的时候,我们使用strip()函数去掉它们,然后使用print语句提供的回车。

   3.   使用SocketServer处理多连接

   上面的例子一次只能连接一个客户机并出力它的请求,如果要处理多连接问题,那么有三种主要的方法能实现这个目的:分叉(forking)、线程(threading)以及异步I/O(asynchronous I/O)。通过对SocketServer服务器使用混入类(mix-in class),派生进程和线程很容易处理。即使要自己实现它们,这些方法也很容易使用。它们确实有缺点:分叉占据资源,并且如果有太多的客户端时分叉不能很好分叉(尽管如此,对于合理数量的客户端,分叉在现代的UNIX或者Linux系统中是很高效的,如果有一个多CPU系统,那系统效率会更高);线程处理能导致同步问题。使用SocketServer框架创建分叉或者线程服务器非常简单:

分叉SocketServer服务器:

#!/usr/bin/env python
 
from SocketServer import (TCPServer as TCP,
                          StreamRequestHandler as SRH,
                          ForkingMixIn as FMI)
from time import ctime
 
HOST = ''
PORT = 12346
ADDR = (HOST, PORT)
 
class Server(FMI, TCP):
    pass
 
class MyRequestHandler(SRH):
    def handle(self):
        print '...connected from:', self.client_address
        self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline()))
 
tcpServ = Server(ADDR, MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()

多线程SocketServer服务器:

#!/usr/bin/env python
 
from SocketServer import (TCPServer as TCP,
                          StreamRequestHandler as SRH,
                          ThreadingMixIn as TMI)
from time import ctime
 
HOST = ''
PORT = 12346
ADDR = (HOST, PORT)
 
class Server(TMI, TCP):
    pass
 
class MyRequestHandler(SRH):
    def handle(self):
        print '...connected from:', self.client_address
        self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline()))
 
tcpServ = Server(ADDR, MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()
相关文章
|
1月前
|
Python
python socket 简单通信
python socket 简单通信
33 1
|
2天前
|
网络协议 安全 网络安全
震惊!Python Socket竟能如此玩转网络通信,基础到进阶全攻略!
【9月更文挑战第12天】在网络通信中,Socket编程是连接不同应用与服务的基石。本文通过问答形式,从基础到进阶全面解析Python Socket编程。涵盖Socket的重要性、创建TCP服务器与客户端、处理并发连接及进阶话题如非阻塞Socket、IO多路复用等,帮助读者深入了解并掌握网络通信的核心技术。
16 6
|
1天前
|
消息中间件 网络协议 网络安全
解锁Python Socket新姿势,进阶篇带你玩转高级网络通信技巧!
【9月更文挑战第13天】在掌握了Python Socket编程基础后,你是否想进一步提升技能?本指南将深入探讨Socket编程精髓,包括从阻塞到非阻塞I/O以提高并发性能,使用`select`进行非阻塞操作示例;通过SSL/TLS加密通信保障数据安全,附带创建SSL服务器的代码实例;以及介绍高级网络协议与框架,如HTTP、WebSocket和ZeroMQ,帮助你简化复杂应用开发。通过学习这些高级技巧,你将在网络编程领域更进一步。
11 2
|
18天前
|
网络协议 测试技术 网络安全
Python进行Socket接口测试的实现
在现代软件开发中,网络通信是不可或缺的一部分。无论是传输数据、获取信息还是实现实时通讯,都离不开可靠的网络连接和有效的数据交换机制。而在网络编程的基础中,Socket(套接字)技术扮演了重要角色。 Socket 允许计算机上的程序通过网络进行通信,它是网络通信的基础。Python 提供了强大且易于使用的 socket 模块,使开发者能够轻松地创建客户端和服务器应用,实现数据传输和交互。 本文将深入探讨如何利用 Python 编程语言来进行 Socket 接口测试。我们将从基础概念开始介绍,逐步引导大家掌握创建、测试和优化 socket 接口的关键技能。希望本文可以给大家的工作带来一些帮助~
|
29天前
|
分布式计算 网络协议 Python
Python网络编程:socket编程
Socket 编程是网络编程的重要部分,主要用于在不同计算机之间进行通信。Python 提供了一个非常强大的 socket 库,使得网络编程变得简单和灵活。本篇博文将详细介绍 Python 的 socket 编程,包括基础概念、核心组件、常用功能,并附上一个综合的示例及其运行结果。
|
21天前
|
网络协议 测试技术 网络安全
Python进行Socket接口测试的实现
在现代软件开发中,网络通信是不可或缺的一部分。无论是传输数据、获取信息还是实现实时通讯,都离不开可靠的网络连接和有效的数据交换机制。而在网络编程的基础中,Socket(套接字)技术扮演了重要角色。 Socket 允许计算机上的程序通过网络进行通信,它是网络通信的基础。Python 提供了强大且易于使用的 socket 模块,使开发者能够轻松地创建客户端和服务器应用,实现数据传输和交互。 本文将深入探讨如何利用 Python 编程语言来进行 Socket 接口测试。我们将从基础概念开始介绍,逐步引导大家掌握创建、测试和优化 socket 接口的关键技能。希望本文可以给大家的工作带来一些帮助~
|
23天前
|
网络协议 数据格式 Python
python Socket无限发送接收数据方式
Socket是指套接字,是对网络中不同主机上的应用进程之间进行双向通信的端点的一种抽象。 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。
|
21天前
|
Linux Python
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
|
2月前
|
网络协议 开发者 Python
网络编程小白秒变大咖!Python Socket基础与进阶教程,轻松上手无压力!
【7月更文挑战第25天】在网络技术快速发展的背景下, Python因其简洁的语法和强大的库支持成为学习网络编程的理想选择。
54 5
|
2月前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
27 4