python 套接字_Python套接字

1、客户端/服务器架构

什么是客户端/服务器架构?对于不同的人来说,它意味着不同的东西,这取决于你问谁以及描述的是软件还是硬件系统。在这两种情况中的任何一种下,前提都很简单:服务器就是一系列硬件或软件,为一个或多个客户端(服务的用户)提供所需的“服务”。它存在唯一目的就是等待客户端的请求,并响应它们(提供服务),然后等待更多请求。另一方面,客户端因特定的请求而联系服务器,并发送必要的数据,然后等待服务器的回应,最后完成请求或给出故障的原因。服务器无限地运行下去,并不断地处理请求;而客户端会对服务进行一次性请求,然后接收该服务,最后结束它们之间的事务。客户端在一段时间后可能会再次发出其他请求,但这些都被当作不同的事务。

e7ee6680af4541bbf97545cf5fb6b5c0.png

2、客户端/服务器编程

2.1套接字

套接字的起源可以追溯到20 世纪70 年代,它是加利福尼亚大学的伯克利版本UNIX(称为BSD UNIX)的一部分。因此,有时你可能会听过将套接字称为伯克利套接字或BSD 套接字。套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个程序(又名一个进程)与另一个运行的程序进行通信。这就是所谓的进程间通信(Inter Process Communication,IPC)。有两种类型的套接字:基于文件的和面向网络的。UNIX 套接字是我们所讲的套接字的第一个家族,并且拥有一个“家族名字”AF_UNIX(又名AF_LOCAL,在POSIX1.g 标准中指定),它代表地址家族(address family):UNIX。包括Python 在内的大多数受欢迎的平台都使用术语地址家族及其缩写AF;其他比较旧的系统可能会将地址家族表示成域(domain)或协议家族(protocol family),并使用其缩写PF 而非AF。类似地,AF_LOCAL(在2000~2001 年标准化)将代替AF_UNIX。然而,考虑到后向兼容性,很多系统都同时使用二者,只是对同一个常数使用不同的别名。Python 本身仍然在使用AF_UNIX。因为两个进程运行在同一台计算机上,所以这些套接字都是基于文件的,这意味着文件

系统支持它们的底层基础结构。这是能够说得通的,因为文件系统是一个运行在同一主机上的多个进程之间的共享常量。

第二种类型的套接字是基于网络的,它也有自己的家族名字AF_INET,或者地址家族:因特网。另一个地址家族AF_INET6 用于第6 版因特网协议(IPv6)寻址。此外,还有其他的地址家族,这些要么是专业的、过时的、很少使用的,要么是仍未实现的。在所有的地址家族之中,目前AF_INET 是使用得最广泛的。

Python 2.5 中引入了对特殊类型的Linux 套接字的支持。套接字的AF_NETLINK 家族允许使用标准的BSD 套接字接口进行用户级别和内核级别代码之间的IPC。针对Linux 的另一种特性(Python 2.6 中新增)就是支持透明的进程间通信(TIPC)协议。TIPC 允许计算机集群之中的机器相互通信,而无须使用基于IP 的寻址方式。Python 对TIPC 的支持以AF_TIPC 家族的方式呈现。

2.2套接字地址:主机-端口对

有效的端口号范围为0~65535(尽管小于1024 的端口号预留给了系统)。

2.3面向连接的套接字

TCP 套接字,必须使用SOCK_STREAM 作为套接字类型。

2.4无连接的套接字

实现这种连接类型的主要协议是用户数据报协议(更为人熟知的是其缩写UDP)。为了创建UDP 套接字,必须使用SOCK_DGRAM 作为套接字类型。

3、python中的网络编程

3.1socket 模块

socket模块属性

cd6cdcc7aa60c39009ff54c45a848693.png

33bc0715225273001f1c7796b0dfc9c3.png

74126bb540e3a824579b2999f9abdbbe.png

套接字创建:

socket(socket_family, socket_type, protocol=0)

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

ud pSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

socket对象方法:

8af03f6a852234f8e0dd610f75408518.png

d01285c86f93e541afa609a2749b4d9c.png

e192a407223a11e7afd61d1178c3c2bb.png

服务器创建:

ss = socket() # 创建服务器套接字

ss.bind() # 套接字与地址绑定

ss.listen() # 监听连接

inf_loop: # 服务器无限循环

cs = ss.accept() # 接受客户端连接

comm_loop: # 通信循环

cs.recv()/cs.send() # 对话(接收/发送)

cs.close() # 关闭客户端套接字

ss .close() # 关闭服务器套接字#(可选)

为服务器实现一个智能的退出方案时,建议调用close()方法。

客户端创建:

cs = socket() # 创建客户端套接字

cs.connect() # 尝试连接服务器

comm_loop: # 通信循环

cs.send()/cs.recv() # 对话(发送/接收)

cs .close() # 关闭客户端套接字

I/O多路复用

多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。这样在处理1000个连接时,只需要1个线程监控就绪状态,对就绪的每个连接开一个线程处理就可以了,这样需要的线程数大大减少,减少了内存开销和上下文切换的CPU开销。

举一个例子,模拟一个tcp服务器处理30个客户socket。

假设你是一个老师,让30个学生解答一道题目,然后检查学生做的是否正确,你有下面几个选择:

1. 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡主,全班都会被耽误。

这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。

2. 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。

3. 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。。。

这种就是IO复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。

这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。

c3f75b0eed39daf55b82090965df4731.png

方法:

windows python:

提供: select

Mac Python:

提供: select

Linux Python:

提供: select、poll、epoll

select方法:

select  -在单线程网络服务中器程序中,管理多个套接字连接。

select的原型为(rlist,wlist,xlist[,timeout]),其中rlist是等待读取的对象,wlist是等待写入的对象,xlist是等待异常的对象,最后一个是可选对象,指定等待的时间,单位是s.

select()方法的返回值是准备好的对象的三元组,若在timeout的时间内,没有对象准备好,那么返回值将是空的列表,它采用的是轮询的方式来实现异步通信的。

服务器:

#!/usr/bin/python

'test TCP server'

from socket import *

from time import ctime

import select

import sys

HOST = ''

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

tcpSerSock = socket(AF_INET, SOCK_STREAM)

tcpSerSock.bind(ADDR)

tcpSerSock.listen(5)

input = [tcpSerSock, sys.stdin] #input是一个列表,初始有欢迎套接字以及标准输入

while True:

print 'waiting for connection...'

tcpCliSock, addr = tcpSerSock.accept()

print '...connected from:',addr

input.append(tcpCliSock) #将服务套接字加入到input列表中

while True:

readyInput,readyOutput,readyException = select.select(input,[],[]) #从input中选择,轮流处理client的请求连接(tcpSerSock),client发送来的消息(tcpCliSock),及服务器端的发送消息(stdin)

for indata in readyInput:

if indata==tcpCliSock: #处理client发送来的消息

data = tcpCliSock.recv(BUFSIZ)

print data

if data=='':

input.remove(tcpCliSock)

break

else: #处理服务器端的发送消息

data = raw_input('>')

if data=='':

tcpCliSock.send('%s' %(data))

input.remove(tcpCliSock)

break

tcpCliSock.send('[%s] %s' %(ctime(), data))

if data=='':

break

tcpCliSock.close()

tcpSerSock.close()

客户端:

#!/usr/bin/python

'test tcp client'

from socket import *

from time import ctime

import select

import sys

HOST = 'localhost'

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

tcpCliSock = socket(AF_INET, SOCK_STREAM)

tcpCliSock.connect(ADDR)

input = [tcpCliSock,sys.stdin]

while True:

readyInput,readyOutput,readyException = select.select(input,[],[])

for indata in readyInput:

if indata==tcpCliSock:

data = tcpCliSock.recv(BUFSIZ)

print data

if data=='':

break

else:

data = raw_input('>')

if data=='':

tcpCliSock.send('%s' %(data))

break

tcpCliSock.send('[%s] %s' %(ctime(), data))

if data=='':

break

tcpCliSock.close()

3.2 socketserver 模块

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。

该模块中的类

b87983f904825bca5808c0334d59163c.png

基本用法:

创建SocketServer TCP 服务器

# 请求处理程序MyRequestHandler,作为SocketServer

# 中StreamRequestHandler 的一个子类,并重写了它的handle()方法,该方法在基类Request 中

# 默认情况下没有任何行为。

# def handle(self):

# pass

# 当接收到一个来自客户端的消息时,它就会调用handle()方法。而StreamRequestHandler

# 类将输入和输出套接字看作类似文件的对象,因此我们将使用readline()来获取客户端消息,

# 并利用write()将字符串发送回客户端。

from socketserver import TCPServer as TCP,StreamRequestHandler as SRH

from time import ctime

HOST=''

PORT=''

ADDR=(HOST,PORT)

class MyRequestHandle(SRH):

def handle(self):

print('...connected from:{0}',self.client_address)

self.wfile.write('[%s]%s'%(ctime(),self.rfile.readline()))

tcpSever=TCP(ADDR,MyRequestHandle)

print('waiting for connection')

tcpSever.serve_forever()

创建TCP客户端

from socket import *

HOST='localhost'

PORT=''

BUFSIZ=1024

ADDR=(HOST,PORT)

while True:

tcpClisocket=socket(ADDR,SOCK_STREAM)

tcpClisocket.connect(ADDR)

data=input('>')

if not data:

break

# 因为这里使用的处理程序类对待套

# 接字通信就像文件一样,所以必须发送行终止符(回车和换行符)

# 而服务器只是保留并重用这里发送的终止符。当得到从服务器返回的消息时,用strip()

# 函数对其进行处理并使用由print声明自动提供的换行符。

tcpClisocket.send('%s\r\n'%data)

data=tcpClisocket.recv(BUFSIZ)

if not data:

break

print(data.strip())

tcpClisocket.close()

ThreadingTCPServer

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

创建一个继承自 SocketServer.BaseRequestHandler 的类

类中必须定义一个名称为 handle 的方法

启动ThreadingTCPServer

a6ca69443b7a925f55a6d42331bff41d.png

# 启动服务端程序

# 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口

# 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass

# 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...

# 当客户端连接到达服务器

# 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求

# 执行 ThreadingMixIn.process_request_thread 方法

# 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)

# 服务器

# #!/usr/bin/env python

# # -*- coding:utf-8 -*-

import SocketServer

class MyServer(SocketServer.BaseRequestHandler):

def handle(self):

# print self.request,self.client_address,self.server

conn = self.request

conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')

Flag = True

while Flag:

data = conn.recv(1024)

if data == 'exit':

Flag = False

elif data == '':

conn.sendall('通过可能会被录音.balabala一大推')

else:

conn.sendall('请重新输入.')

if __name__ == '__main__':

server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)

server.serve_forever()

ForkingTcpSever

ForkingTCPServer和ThreadingTCPServer的使用和执行流程基本一致,只不过在内部分别为请求者建立 “线程”  和 “进程”。

3.3 Twisted模块

Twisted 是一个完整的事件驱动的网络框架,利用它既能使用也能开发完整的异步网络应用程序和协议。它提供了大量的支持来建立完整的系统,包括网络协议、线程、安全性和身份验证、聊天/ IM、DBM 及RDBMS 数据库集成、Web/因特网、电子邮件、命令行参数、GUI 集成工具包等。与SocketServer 类似,Twisted 的大部分功能都存在于它的类中。

Twisted Reactor TCP服务器

基于protocol 类创建TSServProtocol,重写connectionMade()和dataReceived()方法,当一个客户端连接到服务器时就会执行connectionMade()方法,而当服务器接收到客户端通过网络发送的一些数据时就会调用dataReceived()方法。

reactor 会作为该方法的一个参数在数据中传输,这样就能在无须自己提取它的情况下访问它。在服务器代码的最后部分中,创建了一个协议工厂。它之所以被称为工厂,是因为每次得到一个接入连接时,都能“制造”协议的一个实例。然后在reactor 中安装一个TCP 监听器,以此检查服务请求。当它接收到一个请求时,就会创建一个TSServProtocol 实例来处理那个客户端的事务。

from twisted.internet import protocol,reactor

from time import ctime

PORT=21567

class TSServProtocal(protocol.Protocol):

def connectionMade(self):

clnt=self.clnt=self.transport.getPeer().host

print('...conected from:',clnt)

def dataReceived(self, data):

self.transport.write('[%s]%s'%(ctime(),data))

factory=protocol.Factory()

factory.protocol=TSServProtocal

print('waiting for conneciton')

reactor.listenTCP(PORT,factory)

reactor.run()

Twisted Reactor TCP客户端

from twisted.internet import protocol, reactor

HOST='localhost'

PORT=21567

class TSClntProtocal(protocol.Protocol):

def sendData(self):

data=input('>')

if data:

print('...sending%...'%data)

else:

self.transport.loseConnection()

def connectionMade(self):

self.sendData()

def dataReceived(self, data):

print(data)

class TSClntFactory(protocol.Factory):

protocol=TSClntProtocal

clientConnectionLost=clientConnectionFailed=\

lambda self,connector,reason:reactor.stop()

reactor.connectTCP(HOST,PORT,TSClntFactory())

reactor.run()

python套接字解决tcp粘包问题

python套接字解决tcp粘包问题 目录 什么是粘包 演示粘包现象 解决粘包 实际应用 什么是粘包 首先只有tcp有粘包现象,udp没有粘包 socket收发消息的原理 发送端可以是一K一K地发送数 ...

python套接字编程实现ntp服务和远程命令执行

python套接字编程实现ntp服务和远程命令执行 目录 基于udp实现ntp服务 基于tcp实现远程命令执行 基于udp实现远程命令执行 tcp与udp的比较 前面关于套接字基础请查阅 https: ...

python套接字编程基础

python套接字编程 目录 socket是什么 套接字的工作流程 基于tcp的套接字 基于udp的套接字 socket是什么 客户端/服务器架构(C/S架构) 服务端:提供服务的一端 客户端:请求服 ...

Python套接字编程(1)——socket模块与套接字编程

在Python网络编程系列,我们主要学习以下内容: 1. socket模块与基本套接字编程 2. socket模块的其他网络编程功能 3. SocketServer模块与简单并发服务器 4. 异步编程 ...

python套接字基本使用

socket socket通常也称作"套接字",用于描述IP地址和端口,应用程序通常通过"套接字"向网络发出请求或者应答网络请求,可以认为是一种计算机网络的数据 ...

day29 python 套接字socket TCP udp 形式发送信息的区别

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

python 套接字Socket详解

socket简介 1. 什么是socket ? socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是: 它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多 ...

Python套接字之UDP

目录 基于UDP的socket 发送消息 接收消息 基于UDP的socket 面向无连接的不可靠数据传输,可以没有服务器端,只不过没有服务器端,发送的数据会被直接丢弃,并不能到达服务器端 发送消息 在 ...

Python 套接字的使用 (1)

获取设备名称和IPv4地址 socket.gethostname() socket.gethostbyname(host_name)   def print_machine_info(): host_ ...

随机推荐

marquee 实现首尾相连循环滚动效果

可以实现多种滚动效果,无需js控制.使用marquee标签不仅可以滚动文字,也可以滚动图片,表格等  marquee标签不是HTML3.2 ...

CentOS6.3编译安装Memcached集群分布式缓存代理Magent-0.6出错汇总

参考文章:Memcached集群/分布式/高可用 及 Magent缓存代理搭建过程 详解,搭建Magent,在编译的过程中会出现很多错误: #编译安装安装magent到 /usr/local/mage ...

怎么用CorelDRAW插入、删除与重命名页面

在绘图之前,页面的各种设置也是一项重要的工作,本文主要讲解如何在CorelDRAW中插入.删除.重命名页面等操作.在CorelDRAW的绘图工作中,常常需要在同一文档中添加多个空白页面,删除一些无用的 ...

Lrc歌词批量下载助手 MP3歌词批量下载助手

Lrc歌词批量下载助手  MP3歌词批量下载助手   易歌词的服务器已经挂掉,各个主流播放器已不提供明确的下载Lrc服务,当上G的MP3文件遇上苦逼的播放器,二缺就诞生了!本软件就是在这种背景下诞生的 ...

HDU - 1394 Minimum Inversion Number (线段树求逆序数)

Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs ( ...

java-cef嵌入基于Chrome内核浏览器,做页面爬虫(可以尽在ajax异步请求数据)

1 CentOS 7.0 上安装和配置 VNC 服务器 2.1 2.1.1 首先,我们需要一个可用的桌面环境(X-Window),如果没有的话要先安装一个. 注意:以下命令必须以 root 权限运行. ...

JavaScript继承总结

1.创建对象 1.字面量对象 2.构造函数 3.Object.create //1.字面量 var obj={ name: '字面量', show: function(){ console.log(t ...

【转】window.onerror跨域问题

What the heck is "Script error"? Ben Vinegar/ May 17, 2016 If you’ve done any work with th ...

LeetCode数组解题模板

一.模板以及题目分类 1.头尾指针向中间逼近 ; ; while (pos1

a标签和p标签不能设置margin

经常会发现正常div的属性在a标签上或者p标签上都不管用,这是因为a标签和p标签都不是盒子模型. 例如:

&l ...
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值