python select网络编程详细介绍
刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程
一、socket模块
socket
— Low-level networking interface
This module provides access to the BSD socket interface. It is available on all modern Unix systems, Windows, MacOS, and probably additional platforms.
更多详细信息请看官方文档 https://docs.python.org/3/library/socket.html
1、Socket类型
socket 常量 |
描述 |
socket.AF_UNIX |
只能够用于单一的Unix系统进程间通信 |
socket.AF_INET |
服务器之间网络通信 |
socket.AF_INET6 |
IPv6 |
socket.SOCK_STREAM |
流式socket , for TCP |
socket.SOCK_DGRAM |
数据报式socket , for UDP |
socket.SOCK_RAW |
原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。 |
socket.SOCK_SEQPACKET |
可靠的连续数据包服务 |
创建TCP Socket: |
|
创建UDP Socket: |
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) |
2、socket函数
服务器端 Socket 函数
Socket 函数 | 描述 |
---|---|
s.bind(address) | 将套接字绑定到地址,在AF_INET下,以tuple(host, port)的方式传入,如s.bind((host, port)) |
s.listen(backlog) | 开始监听TCP传入连接,backlog指定在拒绝链接前,操作系统可以挂起的最大连接数,该值最少为1,大部分应用程序设为5就够用了 |
s.accpet() | 接受TCP链接并返回(conn, address),其中conn是新的套接字对象,可以用来接收和发送数据,address是链接客户端的地址。 |
客户端 Socket 函数
Socket 函数 | 描述 |
---|---|
s.connect(address) | 链接到address处的套接字,一般address的格式为tuple(host, port),如果链接出错,则返回socket.error错误 |
s.connect_ex(address) | 功能与s.connect(address)相同,但成功返回0,失败返回errno的值 |
公共 Socket 函数
Socket 函数 | 描述 |
---|---|
s.recv(bufsize[, flag]) | 接受TCP套接字的数据,数据以字符串形式返回,buffsize指定要接受的最大数据量,flag提供有关消息的其他信息,通常可以忽略 |
s.send(string[, flag]) | 发送TCP数据,将字符串中的数据发送到链接的套接字,返回值是要发送的字节数量,该数量可能小于string的字节大小 |
s.sendall(string[, flag]) | 完整发送TCP数据,将字符串中的数据发送到链接的套接字,但在返回之前尝试发送所有数据。成功返回None,失败则抛出异常 |
s.recvfrom(bufsize[, flag]) | 接受UDP套接字的数据u,与recv()类似,但返回值是tuple(data, address)。其中data是包含接受数据的字符串,address是发送数据的套接字地址 |
s.sendto(string[, flag], address) | 发送UDP数据,将数据发送到套接字,address形式为tuple(ipaddr, port),指定远程地址发送,返回值是发送的字节数 |
s.close() | 关闭套接字 |
s.getpeername() | 返回套接字的远程地址,返回值通常是一个tuple(ipaddr, port) |
s.getsockname() | 返回套接字自己的地址,返回值通常是一个tuple(ipaddr, port) |
s.setsockopt(level, optname, value) | 设置给定套接字选项的值 |
s.getsockopt(level, optname[, buflen]) | 返回套接字选项的值 |
s.settimeout(timeout) | 设置套接字操作的超时时间,timeout是一个浮点数,单位是秒,值为None则表示永远不会超时。一般超时期应在刚创建套接字时设置,因为他们可能用于连接的操作,如s.connect() |
s.gettimeout() | 返回当前超时值,单位是秒,如果没有设置超时则返回None |
s.fileno() | 返回套接字的文件描述 |
s.setblocking(flag) | 如果flag为0,则将套接字设置为非阻塞模式,否则将套接字设置为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
s.makefile() | 创建一个与该套接字相关的文件 |
3、socket异常
Exception | 解释 |
socket.error |
由Socket相关错误引发 |
socket.herror | 由地址相关错误引发 |
socket.gaierror | 由地址相关错误,如getaddrinfo()或getnameinfo()引发 |
socket.timeout | 当socket出现超时时引发。超时时间由settimeout()提前设定 |
二、socket编程
1、基于TCP(面向连接)的Socket编程(C++)
(5. 关闭套接字(closesocket)
3、socket tcp 编程实例,c/s程序
#!/bin/env python
# -*- coding:utf8 -*-
"""
server.py
""" import socket host = ('10.1.32.80', 33333)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 网络通信, TCP流
s.bind(host)
s.listen(5) # listen 5 client
print "i'm waiting for connection..." while True:
conn, addr = s.accept() # connection and ip address
print 'connected by', addr
while True:
data = conn.recv(1024)
print "receive from %s:%s" % (addr, data)
conn.sendall("server receive your messages, good bye.")
conn.close()
break
# s.close()
#!/bin/env python
# -*- coding:utf8 -*- import socket
"""
client.py
""" host = ('10.1.32.80', 33333)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 网络通信, TCP流
s.connect(host) while True:
msg = raw_input("Please input message: ")
try:
s.sendall(msg)
except socket.error:
print "i'm die, bye bye~"
break
data = s.recv(1024)
print data
if "good bye" in data:
break
s.close()
三、基于select的网络编程
1、select介绍
2、使用select编程,聊天室程序如下。运行多个client,则可互相聊天,输入"exit"即可退出
服务器代码
#!/bin/env python
#-*- coding:utf8 -*- """
server select
""" import sys
import time
import socket
import select
import logging
import Queue g_select_timeout = 10 class Server(object):
def __init__(self, host='10.1.32.80', port=33333, timeout=2, client_nums=10):
self.__host = host
self.__port = port
self.__timeout = timeout
self.__client_nums = client_nums
self.__buffer_size = 1024 self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setblocking(False)
self.server.settimeout(self.__timeout)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) #keepalive
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #端口复用
server_host = (self.__host, self.__port)
try:
self.server.bind(server_host)
self.server.listen(self.__client_nums)
except:
raise self.inputs = [self.server] #select 接收文件描述符列表
self.outputs = [] #输出文件描述符列表
self.message_queues = {}#消息队列
self.client_info = {} def run(self):
while True:
readable , writable , exceptional = select.select(self.inputs, self.outputs, self.inputs, g_select_timeout)
if not (readable or writable or exceptional) :
continue for s in readable :
if s is self.server:#是客户端连接
connection, client_address = s.accept()
#print "connection", connection
print "%s connect." % str(client_address)
connection.setblocking(0) #非阻塞
self.inputs.append(connection) #客户端添加到inputs
self.client_info[connection] = str(client_address)
self.message_queues[connection] = Queue.Queue() #每个客户端一个消息队列 else:#是client, 数据发送过来
try:
data = s.recv(self.__buffer_size)
except:
err_msg = "Client Error!"
logging.error(err_msg)
if data :
#print data
data = "%s %s say: %s" % (time.strftime("%Y-%m-%d %H:%M:%S"), self.client_info[s], data)
self.message_queues[s].put(data) #队列添加消息 if s not in self.outputs: #要回复消息
self.outputs.append(s)
else: #客户端断开
#Interpret empty result as closed connection
print "Client:%s Close." % str(self.client_info[s])
if s in self.outputs :
self.outputs.remove(s)
self.inputs.remove(s)
s.close()
del self.message_queues[s]
del self.client_info[s] for s in writable: #outputs 有消息就要发出去了
try:
next_msg = self.message_queues[s].get_nowait() #非阻塞获取
except Queue.Empty:
err_msg = "Output Queue is Empty!"
#g_logFd.writeFormatMsg(g_logFd.LEVEL_INFO, err_msg)
self.outputs.remove(s)
except Exception, e: #发送的时候客户端关闭了则会出现writable和readable同时有数据,会出现message_queues的keyerror
err_msg = "Send Data Error! ErrMsg:%s" % str(e)
logging.error(err_msg)
if s in self.outputs:
self.outputs.remove(s)
else:
for cli in self.client_info: #发送给其他客户端
if cli is not s:
try:
cli.sendall(next_msg)
except Exception, e: #发送失败就关掉
err_msg = "Send Data to %s Error! ErrMsg:%s" % (str(self.client_info[cli]), str(e))
logging.error(err_msg)
print "Client: %s Close Error." % str(self.client_info[cli])
if cli in self.inputs:
self.inputs.remove(cli)
cli.close()
if cli in self.outputs:
self.outputs.remove(s)
if cli in self.message_queues:
del self.message_queues[s]
del self.client_info[cli] for s in exceptional:
logging.error("Client:%s Close Error." % str(self.client_info[cli]))
if s in self.inputs:
self.inputs.remove(s)
s.close()
if s in self.outputs:
self.outputs.remove(s)
if s in self.message_queues:
del self.message_queues[s]
del self.client_info[s] if "__main__" == __name__:
Server().run()
客户端代码
#!/usr/local/bin/python
# *-* coding:utf-8 -*- """
client.py
""" import sys
import time
import socket
import threading class Client(object):
def __init__(self, host, port=33333, timeout=1, reconnect=2):
self.__host = host
self.__port = port
self.__timeout = timeout
self.__buffer_size = 1024
self.__flag = 1
self.client = None
self.__lock = threading.Lock() @property
def flag(self):
return self.__flag @flag.setter
def flag(self, new_num):
self.__flag = new_num def __connect(self):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#client.bind(('0.0.0.0', 12345,))
client.setblocking(True)
client.settimeout(self.__timeout)
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #端口复用
server_host = (self.__host, self.__port)
try:
client.connect(server_host)
except:
raise
return client def send_msg(self):
if not self.client:
return
while True:
time.sleep(0.1)
#data = raw_input()
data = sys.stdin.readline().strip()
if "exit" == data.lower():
with self.__lock:
self.flag = 0
break
self.client.sendall(data)
return def recv_msg(self):
if not self.client:
return
while True:
data = None
with self.__lock:
if not self.flag:
print 'ByeBye~~'
break
try:
data = self.client.recv(self.__buffer_size)
except socket.timeout:
continue
except:
raise
if data:
print "%s\n" % data
time.sleep(0.1)
return def run(self):
self.client = self.__connect()
send_proc = threading.Thread(target=self.send_msg)
recv_proc = threading.Thread(target=self.recv_msg)
recv_proc.start()
send_proc.start()
recv_proc.join()
send_proc.join()
self.client.close() if "__main__" == __name__:
Client('10.1.32.80').run()
四、多路IO复用介绍和区别
python select网络编程详细介绍的更多相关文章
- Python 006- python socket编程详细介绍
转自https://blog.csdn.net/rebelqsp/article/details/22109925 Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供 ...
- Python socket网络编程(通信介绍)
socket通信介绍 通信介绍(一) 1.所有网络协议的基础就是:socket 2.socket对TCP与UDP协议封装,让用户进行简单操作. 3.socket只做两件事:发 send,收 rec ...
- python之网络编程
本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...
- Python Socket网络编程详解
Socket 简介 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. s ...
- Socket网络编程基本介绍
一,socket的起源 socket一词的起源 在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的, 撰写者为Stephen Carr.Steve Crocker和Vi ...
- Python高级网络编程系列之第一篇
在上一篇中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握 ...
- python基础网络编程--转
python之网络编程 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的 ...
- python 基础网络编程2
python 基础网络编程2 前一篇讲了socketserver.py中BaseServer类, 下面介绍下TCPServer和UDPServer class TCPServer(BaseServer ...
- python 基础网络编程1
python 基础网络编程1 Source code: Lib/socketserver.py lib的主目录下有一个sockserver.py文件, 里面是python基本的网络编程模型 共有一个b ...
随机推荐
- ABP入门系列(1)——学习Abp框架之实操演练
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
- Jade模板引擎让你飞
写在前面:现在jade改名成pug了 一.安装 npm install jade 二.基本使用 1.简单使用 p hello jade! 渲染后: <p>hello jade!</p ...
- java基础_集合List与Set接口
List接口继承了Collection的方法 当然也有自己特有的方法向指定位置添加元素 add(索引,添加的元素); 移除指定索引的元素 remove(索引) 修改指定索引的元素 set ...
- UniqueIdentifier 数据类型 和 GUID 生成函数
UniqueIdentifier 数据类型用于存储GUID的值,占用16Byte. SQL Server将UniqueIdentifier存储为16字节的二进制数值,Binary(16),按照特定的格 ...
- CRL快速开发框架系列教程七(使用事务)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- 设计模式C#合集--工厂方法模式
简单工厂,代码: public interface ISpeak { public void Say(); } public class Hello : ISpeak { public void Sa ...
- H5 canvas的 width、height 与style中宽高的区别
Canvas 的width height属性 1.当使用width height属性时,显示正常不会被拉伸:如下 <canvas id="mycanvas" width=&q ...
- HTML5 程序设计 - 使用HTML5 Canvas API
请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...
- win10电脑优化
Windows10必做的优化 --道心 关闭服务 右键点击"此电脑",选择"管理",进入"计算机管理"窗口. 在左侧的菜单选择"服 ...
- 自定义ConfigSection
CCustom configuration section with intelisense