套接字基础
服务器端代码
#coding:UTF-8
from socket import *
myHost = ''
myPort = 50007
socketobj = socket(AF_INET,SOCK_STREAM)
socketobj.bind((myHost,myPort))
socketobj.listen(5)
while True:
connection,address = socketobj.accept()
print('Server connected by ', address)
while True:
data = connection.recv(1024)
print('Client ',data)
if not data:break
connection.send(b'Echo=>'+data)
connection.close()
客户端代码
#coding:UTF-8
from socket import *
serverHost = 'localhost'
serverPort = 50007
message = [b'Hello network world']
socketobj = socket(AF_INET,SOCK_STREAM)
socketobj.connect((serverHost,serverPort))
for line in message:
socketobj.send(line)
data = socketobj.recv(1024)
print('Client recv: ',data)
socketobj.close()
代码解读:
socketobj = socket(AF_INET,SOCK_STREAM)
使用socket模块创建一个套接字对象。里面的参数是固定的AF_INET意味着IP协议地址,SOCK_STREAM意味着TCP传输协议
socketobj.bind((myHost,myPort))
把套接字对象与一个地址关联起来。生成IP地址。主机名通常是一个空字符串
socketobj.listen(5)
开始监听到来的客户端连接,并允许保留五个挂起的请求。在新请求被拒绝之前,传递的值通过操作系统设置到客户端排队请求
connection,address = socketobj.accept()
当请求发生后,accpet调用返回一个全新的套接字对象,在这个套接字对象上,数据可以在连接的客户端发生转移。与客户端的通讯发生在connection上,即新的套接字上。address是连接客户端的互联网地址。
data = connection.recv(1024)
从客户端读取发送的消息,最多1024个字节。当请求结束后会返回一个空字符串。
connection.send(b'Echo=>'+data)
发送新的数据到客户端
客户端的代码差不多
多线程服务器
#coding:utf-8
import time,_thread as thread
from socket import *
myHost = ''
myPort = 50007
socketobj = socket(AF_INET,SOCK_STREAM)
socketobj.bind((myHost,myPort))
socketobj.listen(5)
def now():
return time.ctime(time.time())
def handleClient(connection):
time.sleep(3)
while True:
data = connection.recv(1024)
if not data:break
reply = 'Echo=>%s at %s'%(data,now())
connection.send(reply.encode())
connection.close()
def dispatcher():
while True:
connection,address = socketobj.accept()
print('Server connected by ',address,end = ' ')
print('at',now())
thread.start_new_thread(handleClient,(connection,))
dispatcher()
dispatcher程序把每个传入的客户端连接请求,指定到新派生的运行handleClient函数的线程中。因此服务器可以同时处理多个客户端,主要的调度程序可以迅速回到顶端。
标准库服务器类
#coding:UTF-8
import socketserver,time
myHost = ''
myPort = 50007
def now():
return time.ctime(time.time())
class MyClientHandler(socketserver.BaseRequestHandler):
def handle(self):
print(self.client_address,now())
time.sleep(5)
while True:
data = self.request.recv(1024)
if not data:break
reply = 'Echo=%s at %s'%(data,now())
self.request.send(reply.encode())
self.request.close()
if __name__ == '__main__':
myaddr = (myHost,myPort)
server = socketserver.ThreadingTCPServer(myaddr,MyClientHandler) #具体处理的子类
server.serve_forever() #永久开启
基于select的响应服务器
使用select并行处理多个客户端。使用select模块手动在套接字之间多重通道传输
#coding:utf-8
import time
from select import select
from socket import socket, AF_INET,SOCK_STREAM
def now():return time.ctime(time.time())
myHost = ''
myPort = 50007
mainsocks,readsocks,writesocks = [],[],[]
portsock = socket(AF_INET,SOCK_STREAM)
portsock.bind((myHost,myPort))
portsock.listen(5)
mainsocks.append(portsock)
readsocks.append(portsock)
while True:
readables,writeables,exceptions = select(readsocks,writesocks,[])
for sockobj in readables:
if sockobj in mainsocks:
newsock,address = sockobj.accept()
print('Connect: ',address,id(newsock))
readsocks.append(newsock)
else:
data = sockobj.recv(1024)
print('\tgot ',data,'on',id(sockobj))
if not data:
sockobj.close()
readsocks.remove(sockobj)
else:
reply = 'Echo=>%s at %s'%(data,now())
sockobj.send(reply.encode())
select调用细节
从形式上看,select可以调节可选择对象的三种列表(输入源、输出源和特殊条件)
select.select(rlist, wlist, xlist[, timeout])
rlist,wlist,xlist分别为需要异步处理的读socket队列, 写socket队列(一般不用), 和错误socket队列, 返回事件的读写和错误socket队列