本文简要介绍对套接字的网络编程。套接字是结算及网络数据结构,体现的是“通信端点”的概念。网络应用程序在进行任何通信之前,必须先创建套接字。
一、主要函数介绍:
Python中的网络编程,主要使用socket模块的函数。
socket =》创建套接字对象,socket(s ocket_family , socket_type , protocol =0)
服务器端的方法:
bind =》绑定地址到套接字
listen =》启动TCP监听
accept =》 接受客户端连接
客户端的方法:
connect =》初始化一个TCP服务连接
数据发送和接收:
recv =》接收数据
send =》发送数据
二、服务器端简单的socket编程
1、创建socket:
import socket
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 100
#一般取1024,可以自己根据需要调整。
ADDR = (HOST, PORT)
# 创建socket并监听本地端口.
tcpServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServerSock.bind(ADDR)
tcpServerSock.listen(5)
2、接受客户端连接,接收并发送数据
print("等待连接......")
tcpClientSock, addr = tcpServerSock.accept()
print("... 客户端的地址为:", addr)
while True:
#内循环,处理客户端数据的发送和接收。
data = tcpClientSock.recv(BUFSIZE)
if not data:
break
recData = data.decode() #二进制数据转换为字符串。默认utf-8
print("从客户端收到的数据:", recData)
sendData = "[%s] %s"%(ctime(), recData)
tcpClientSock.send(sendData.encode())
tcpClientSock.close()
tcpServerSock.close()
三、客户端socket编程
1、建立TCP连接
import socket
HOST = 'LOCALHOST'
PORT = 21567
BUFSIZE = 100
ADDR = (HOST, PORT)
tcpClientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientSock.connect(ADDR)
2、定义发送函数
def send01(sock,
msg):
# 在网络不忙的时候,send函数每一次都会将全部的数据发送出去,一帮情况下会工作的很好。
sock.send(msg.encode())
3、发送数据到服务器并接收服务器的数据
data = input('> ')
if not data:
break
sendtotal(tcpClientSock, data)
data = tcpClientSock.recv(BUFSIZE)
if not data:
break
recData = data.decode() #将二进制数据转换为字符串数据。
print("从服务器上收到的数据:%s"%(recData))
4、网络繁忙时发送数据的方法
def sendtotal(sock,
msg):
#判断send发送的字节数, 直到全部发送完。
totalsent = 0
data = msg.encode()
datalen = len(data)
while totalsent < datalen:
sent = sock.send(data[totalsent:])
if sent == 0:
raise RuntimeError("socket连接中断")
totalsent = totalsent + sent
四、并发socket编程
上述简单的socket编程方法,最多只能处理一个客户端的连接。python具有强大的线程处理能力,我们可以将线程与socket编程混合到一起,就可以同时处理多个客户端的连接。
1、自定义socket线程类:
class SocketThread(threading.Thread):
"""自定义socket线程类"""
def __init__(self,
sock):
threading.Thread.__init__(self)
self.sock = sock
def run(self):
while True:
# 内循环,处理客户端数据的发送和接收。
data = self.sock.recv(BUFSIZE)
if not data:
break
recData = data.decode() # 二进制数据转换为字符串。默认utf-8
print("从客户端收到的数据:", recData)
sendData = "[%s] %s" % (ctime(), recData)
self.sock.send(sendData.encode())
self.sock.close()
2、SocketThread的使用
def client_thread(sock):
t = SocketThread(sock)
return t
pass
#外循环,等待客户端连接
while True:
print("等待连接......")
tcpClientSock, addr = tcpServerSock.accept()
print("... 客户端的地址为:", addr)
ct = client_thread(tcpClientSock)
ct.start() #启动线程
5、非阻塞socket编程
在使用线程来处理多个socket连接的问题时,受限于机器资源,线程是昂贵且有限的资源,同时处理的socket连接数毕竟有限。
下面就介绍一下python中非阻塞socket是如何处理的。
1、简介:
非阻塞socket编程主要依赖于select模块,该模块提供了特定平台的I/O监视函数。最轻便的方法就是POSIX功能的select()函数,在unix和windows平台上都可用。
readable, writable, exceptional = select.select(inputs, outputs, inputs)
select方法会返回三个socket列表,分别为读列表,写列表,异常列表,然后分别对这三个列表的socket进行处理。
2、select方法的使用:
import socket
import select
import queue
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 1024
#一般取1024,可以自己根据需要调整。
ADDR = (HOST, PORT)
# 创建socket并监听本地端口.
tcpServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServerSock.setblocking(0)
tcpServerSock.bind(ADDR)
tcpServerSock.listen(5)
# 准备读数据的socket列表。
inputSockets = [tcpServerSock]
#准备发送数据的socket列表。
outputSockets = []
#输出的消息队列。
message_queues = {}
print("等待连接......")
readable, writable, exceptional = select.select(inputSockets, outputSockets, inputSockets)
3、对读socket列表的处理:
for s in readable:
#处理读的socket
if s is tcpServerSock:
clientConnection, addr = tcpServerSock.accept()
print("... 客户端的地址为:", addr)
clientConnection.setblocking(0)
inputSockets.append(clientConnection) #放到读取数据列表中。
#每一个connection一个发送数据的队列。
message_queues[clientConnection] = queue.Queue()
else:
data = s.recv(BUFSIZE)
if data:
print("从%s接收到数据%s" % (s.getpeername(), data.decode()))
message_queues[s].put(data)
if s not
in outputSockets:
outputSockets.append(s)
else:
print("关闭客户端%s,没有读取到数据." % (addr))
if s in outputSockets:
outputSockets.remove(s)
inputSockets.remove(s)
s.close()
#删除当前socket对应的消息队列。
del message_queues[s]
4、对写socket列表的处理:
#处理数据发送队列。
for s in writable:
try:
next_msg = message_queues[s].get_nowait()
except queue.Empty:
print("%s的输出队列为空" % ("ddddd"))
outputSockets.remove(s)
else:
print("发送数据 %s 到 %s" % (next_msg, s.getpeername()))
s.send(next_msg)
5、对异常socket列表的处理:
for s in exceptional:
print("与%s的通信产生异常,连接将被断开"%(s.getpeername()))
inputSockets.remove(s)
if s in outputSockets:
outputSockets.remove(s)
s.close()
del message_queues[s]
备注:
完整源代码可以搜索:python网络编程