Python的标准模块中,既有socket进行底层网络编程,还有各种针对特定网络协议进行编程的模块。
除了标准模块,还可以使用Twisted进行网络编程。
使用socket模块:
socket模块提供了底层的网络接口,可以实现网络上不同计算机之间的通信。
Python的socket实现了BSD套接字标准。
socket是网络连接端点。每个socket都被绑定到指定IP和端口上。
使用socket创建的通信应该有服务端和客户端,服务端首先创建一个socket,并等待客户端的连接。
客户端建立与服务端的socket连接,当连接成功后,客户端和服务端就可以使用socket进行通信了。
socket(family, type, proto)
bind(address)
listen(backlog)
建立服务端:(以下为传送一句话从客户端到服务端,中英文皆可)
# -*-coding:utf-8 -*-
# file: server.py
#
import tkinter
import threading
import socket
class ListenThread(threading.Thread): #监听线程
def __init__(self, edit, server):
threading.Thread.__init__(self)
self.edit=edit #保存窗口中的多行文本框
self.server=server
def run(self): #进入监听状态
while 1:
try:
client, addr=self.server.accept() #等待连接
self.edit.insert(tkinter.END, "连接来自:%s:%d\n" % addr)
data=client.recv(1024) #接收数据
self.edit.insert(tkinter.END, "收到数据:%s \n" % data.decode('utf-8'))
client.send(data) #发送数据
client.close()
self.edit.insert(tkinter.END,"关闭客户端!\n")
except:
self.edit.insert(tkinter.END, "关闭连接\n")
break #结束循环
class Control(threading.Thread): #控制线程
def __init__(self, edit):
threading.Thread.__init__(self)
self.edit=edit
self.event=threading.Event() #创建Event对象
self.event.clear() #清除event标志
def run(self):
server=socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建socket连接
server.bind(('', 1051)) #绑定端口
server.listen(1) #开始监听
self.edit.insert(tkinter.END, '正在等待连接...\n')
self.lt=ListenThread(self.edit,server) #创建监听线程对象
self.lt.setDaemon(True)
self.lt.start() #执行监听线程
self.event.wait() #进入等待状态
server.close
def stop(self):
self.event.set()
class Window:
def __init__(self, root):
self.root=root
self.butlisten=tkinter.Button(root, text='开始监听', command=self.Listen)
self.butlisten.place(x=20,y=15)
self.butclose=tkinter.Button(root, text='停止监听', command=self.Close)
self.butclose.place(x=120,y=15)
self.edit=tkinter.Text(root)
self.edit.place(y=50)
def Listen(self): #按钮事件
self.ctrl=Control(self.edit) #创建控制线程对象
self.ctrl.setDaemon(True)
self.ctrl.start() #执行控制线程
def Close(self):
self.ctrl.stop()
root=tkinter.Tk()
window=Window(root)
root.mainloop()
# -*-coding:utf-8 -*-
# file: client.py
#
import tkinter
import socket
class Window:
def __init__(self, root):
label1=tkinter.Label(root, text='IP')
label1.place(x=5, y=5)
label2=tkinter.Label(root, text='Port')
label2.place(x=5, y=30)
label3=tkinter.Label(root, text='Data')
label3.place(x=5, y=55)
self.entryIP=tkinter.Entry(root)
self.entryIP.insert(tkinter.END, '127.0.0.1')
self.entryIP.place(x=40, y=5)
self.entryPort=tkinter.Entry(root)
self.entryPort.insert(tkinter.END, '1051')
self.entryPort.place(x=40, y=30)
self.entryData=tkinter.Entry(root)
self.entryData.insert(tkinter.END, 'Hello')
self.entryData.place(x=40, y=55)
self.Recv=tkinter.Text(root)
self.Recv.place(y=115)
self.send=tkinter.Button(root, text='发送数据', command=self.Send)
self.send.place(x=40, y=80)
def Send(self): #按钮事件
try:
ip=self.entryIP.get() #获得IP
port=int(self.entryPort.get())
data=self.entryData.get()
client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((ip,port))
client.send(data.encode('utf-8'))
rdata=client.recv(1024)
self.Recv.insert(tkinter.END, '服务器返回: %s \n' % rdata.decode('utf-8'))
client.close()
except:
self.Recv.insert(tkinter.END, '发送错误\n')
root=tkinter.Tk()
window=Window(root)
root.mainloop()
在局域网中传输文件:(上面的例子稍作修改,文件内容可以含中文,但是路径和文件名不能含中文)
服务端:
# -*-coding:utf-8 -*-
# file: fileserver.py
#
import tkinter
import threading
import socket
import os
class ListenThread(threading.Thread):
def __init__(self, edit, server):
threading.Thread.__init__(self)
self.edit=edit
self.server=server
self.file='receive.txt'
def run(self):
while 1:
try:
self.client, addr=self.server.accept() #?
self.edit.insert(tkinter.END, "连接来自:%s:%d\n" % addr)
self.edit.insert(tkinter.END, "开始接收数据:")
file=os.open(self.file, os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_BINARY)
while 1:
rdata=self.client.recv(1024)
if not rdata:
break
os.write(file,rdata)
self.edit.insert(tkinter.END, "......")
os.close(file)
self.client.close()
self.edit.insert(tkinter.END,"\n接收完毕,关闭客户端!\n")
except:
self.edit.insert(tkinter.END, "\n网络错误,关闭连接\n")
break
class Control(threading.Thread):
def __init__(self, edit):
threading.Thread.__init__(self)
self.edit=edit
self.event=threading.Event()
self.event.clear()
def run(self):
server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 1051))
server.listen(1)
self.edit.insert(tkinter.END, '正在等待连接...\n')
self.lt=ListenThread(self.edit,server)
self.lt.setDaemon(True)
self.lt.start()
self.event.wait()
server.close
def stop(self):
self.event.set()
class Window:
def __init__(self, root):
self.root=root
self.butlisten=tkinter.Button(root, text='开始监听', command=self.Listen)
self.butlisten.place(x=20,y=15)
self.butclose=tkinter.Button(root, text='停止监听', command=self.Close)
self.butclose.place(x=120,y=15)
self.edit=tkinter.Text(root)
self.edit.place(y=50)
def Listen(self):
self.ctrl=Control(self.edit)
self.ctrl.setDaemon(True)
self.ctrl.start()
def Close(self):
self.ctrl.stop()
root=tkinter.Tk()
window=Window(root)
root.mainloop()
# -*-coding:utf-8 -*-
# file: fileclient.py
#
import tkinter
import socket
import tkinter.filedialog
import os
class Window:
def __init__(self, root):
label1=tkinter.Label(root, text='IP')
label1.place(x=5, y=5)
label2=tkinter.Label(root, text='Port')
label2.place(x=5, y=30)
label3=tkinter.Label(root, text='文件')
label3.place(x=5, y=55)
self.entryIP=tkinter.Entry(root)
self.entryIP.insert(tkinter.END, '127.0.0.1')
self.entryIP.place(x=40, y=5)
self.entryPort=tkinter.Entry(root)
self.entryPort.insert(tkinter.END, '1051')
self.entryPort.place(x=40, y=30)
self.entryData=tkinter.Entry(root)
self.entryData.insert(tkinter.END, 'Hello')
self.entryData.place(x=40, y=55)
self.openfile=tkinter.Button(root, text='浏览', command=self.Openfile)
self.openfile.place(x=170,y=55)
self.send=tkinter.Button(root, text='发送文件', command=self.Send)
self.send.place(x=40, y=80)
def Send(self):
try:
ip=self.entryIP.get()
port=int(self.entryPort.get())
filename=self.entryData.get()
tt=filename.split('/')
name=tt[len(tt)-1]
client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((ip,port))
client.send(name.encode('utf-8'))
file=os.open(filename, os.O_RDONLY|os.O_EXCL|os.O_BINARY)
while 1:
data=os.read(file,1024)
if not data:
break
client.send(data)
os.close(file)
client.close()
except Exception as e:
print('发送错误',e)
def Openfile(self):
r=tkinter.filedialog.askopenfilename(title='Python tkinter',\
filetypes=[('All files', '*'),\
('Python','*.py *.pyc')])
if r:
self.entryData.delete(0,tkinter.END)#0 can clear it
self.entryData.insert(tkinter.END,r)
root=tkinter.Tk()
window=Window(root)
root.mainloop()
使用urllib,httplib和ftplib:
Python提供的socket模块主要用于底层网络协议,编写程序较为麻烦。
针对常用的HTTP和FTP协议,可以用httplib和ftplib进行访问。
urllib.request模块提供urlopen,urlretrieve方法。
urllib.parse模块
httplib.client模块:
提供HTTPConnection对象和HTTPResponse对象。
创建一个HTTPConnection对象后,可以使用request方法向服务器发送请求。
request(method, url, body, headers)
发送完请求后,可以使用HTTPConnection中的getresponse方法返回一个HTTPResponse对象。Close方法关闭与服务器的连接。
HTTPResponse对象用于处理服务器对所发送请求的回应。
urllib模块可以创建一个简单访问网站的脚本,获取指定页面。使用httplib也可以但是过程复杂,适用于需要用户名和密码认证的网站。而urllib只能简单访问下载页面内容。
# -*-coding: utf-8 -*-
# file: httpurl.py
#
import tkinter
import urllib.request
class Window:
def __init__(self, root):
self.root=root
self.entryUrl=tkinter.Entry(root)
self.entryUrl.place(x=5,y=15)
self.get=tkinter.Button(root, text="下载页面", command=self.Get)
self.get.place(x=160, y=12)
self.edit=tkinter.Text(root)
self.edit.place(x=5, y=50)
def Get(self):
url=self.entryUrl.get()
page=urllib.request.urlopen(url)
data=page.read()
self.edit.insert(tkinter.END, data)
page.close()
root=tkinter.Tk()
window=Window(root)
root.minsize(580,380)
root.mainloop
使用ftplib模块中的FTP类,可以创建FTP连接对象
FTP(host,user,passwd,acct)
建立FTP对象时未指定host,则可以用connect方法连接。同样有login方法。
# -*-coding: utf-8 -*-
# file: pyftp.py
#
from ftplib import FTP
bufsize=1024
def Get(filename):
command='RETR '+filename
ftp.retrbinary(command, open(filename, 'wb').write, bufsize)
print("下载成功")
def Put(filename):
command ='STOR '+filename
filehander=open(filename, 'rb')
ftp.storbinary(command, filehandler, bufsize)
filehander.close()
print("上传成功")
def PWD():
print(ftp.pwd())
def Size(filename):
print(ftp.size(filename))
def Help():
print('''
=================================
Simple Python FTP
=================================
cd 进入文件夹
delete 删除文件
dir 获取当前文件列表
get 下载文件
help 帮助
mkdir 创建文件夹
put 上传文件
pwd 获取当前目录
renmae 重命名文件
rmdir 删除文件夹
size 获取文件大小
''')
server=input("请输入FTP服务器地址:")
ftp=FTP(server)
username=input("请输入用户名:")
password=input("请输入密码:")
ftp.login(username, password)
print (ftp.getwelcome())
actions={'dir':ftp.dir, 'pwd':PWD, 'cd':ftp.cwd, 'get':Get,\
'put':Put, 'help':Help, 'rmdir': frp.rmd,\
'mkdir': ftp.mkd, 'delete':ftp.delete,\
'size':Size, 'rename':ftp.rename}
while true:
print('pyftp>', )
cmds=input()
cmd=str.split(cmds)
try:
if len(cmd)==1:
if str.lower(cmd[0])=='quit':
break
else:
actions[str.lower(cmd[0])]()
elif (len(cmd))==2:
actions[str.lower(cmd[0])](cmd[1])
elif (len(cmd))==3:
actions[str.lower(cmd[0])](cmd[1], cmd[2])
else:
print("输入错误!")
except:
print("命令出错!")
ftp.quit()
# -*-coding: utf-8 -*-
# file: pypop3.py
#
import poplib
import re
import tkinter
class Window:
def __init__(self, root):
label1=tkinter.Label(root, text='POP3')
label2=tkinter.Label(root, text='Port')
label3=tkinter.Label(root, text='用户名')
label4=tkinter.Label(root, text='密码')
label1.place(x=5,y=5)
label2.place(x=5,y=30)
label3.place(x=5,y=55)
label4.place(x=5,y=80)
self.entryPOP=tkinter.Entry(root)
self.entryPort=tkinter.Entry(root)
self.entryUser=tkinter.Entry(root)
self.entryPass=tkinter.Entry(root, show='*')
self.entryPOP.insert(tkinter.END,"pop.163.com")
self.entryPort.insert(tkinter.END,"110")
self.entryUser.insert(tkinter.END,"[email protected]")
self.entryPass.insert(tkinter.END,"lydd22208")
self.entryPOP.place(x=50, y=5)
self.entryPort.place(x=50, y=30)
self.entryUser.place(x=50, y=55)
self.entryPass.place(x=50, y=80)
self.get=tkinter.Button(root, text='收取邮件',command=self.Get)
self.get.place(x=60, y=120)
self.text=tkinter.Text(root)
self.text.place(y=150)
def Get(self):
try:
host=self.entryPOP.get()
port=int(self.entryPort.get())
user=self.entryUser.get()
pw=self.entryPass.get()
pop=poplib.POP3(host)
pop.user(user)
pop.pass_(pw)
stat=pop.stat()
#print(stat)
self.text.insert(tkinter.END, 'Status: %d message(s), %d bytes\n' % stat)
rx_headers=re.compile(r"^(From|To|Subject)")
for n in range(stat[0]):
#print(pop.top(n+1, 10))
response, lines, bytes=pop.top(n+1, 10)
#print(lines)
self.text.insert(tkinter.END, "Message %d (%d bytes)\n" % (n+1, bytes))
self.text.insert(tkinter.END, "-"*30+'\n')
str_lines=[]
for l in lines:
str_lines.append(l.decode('utf-8', 'ignore'))
#str_lines.reverse()
self.text.insert(tkinter.END, "\n".join(filter(rx_headers.match, str_lines)))
self.text.insert(tkinter.END, '\n')
self.text.insert(tkinter.END, "-"*30+'\n')
except Exception as e:
self.text.insert(tkinter.END, "接受错误\n")
root=tkinter.Tk()
window=Window(root)
root.mainloop()
# -*-coding: utf-8 -*-
# file: pysmtp.py
#
import smtplib
import tkinter
class Window:
def __init__(self, root):
label1=tkinter.Label(root, text='SMTP')
label2=tkinter.Label(root, text='Port')
label3=tkinter.Label(root, text='用户名')
label4=tkinter.Label(root, text='密码')
label5=tkinter.Label(root, text='收件人')
label6=tkinter.Label(root, text='主题')
label7=tkinter.Label(root, text='发件人')
label1.place(x=5,y=5)
label2.place(x=5,y=30)
label3.place(x=5,y=55)
label4.place(x=5,y=80)
label5.place(x=5,y=105)
label6.place(x=5,y=130)
label7.place(x=5,y=155)
self.entrySMTP=tkinter.Entry(root)
self.entryPort=tkinter.Entry(root)
self.entryUser=tkinter.Entry(root)
self.entryPass=tkinter.Entry(root, show='*')
self.entryTo=tkinter.Entry(root)
self.entrySub=tkinter.Entry(root)
self.entryFrom=tkinter.Entry(root)
self.entrySMTP.insert(tkinter.END,"smtp.163.com")
self.entryPort.insert(tkinter.END,"25")
self.entryUser.insert(tkinter.END,"[email protected]")
self.entryPass.insert(tkinter.END,"lydd22208")
self.entryTo.insert(tkinter.END,"[email protected]")
self.entrySub.insert(tkinter.END,"test")
self.entryFrom.insert(tkinter.END,"[email protected]")
self.entrySMTP.place(x=50, y=5)
self.entryPort.place(x=50, y=30)
self.entryUser.place(x=50, y=55)
self.entryPass.place(x=50, y=80)
self.entryTo.place(x=50, y=105)
self.entrySub.place(x=50, y=130)
self.entryFrom.place(x=50, y=155)
self.get=tkinter.Button(root, text='发送邮件',command=self.Send)
self.get.place(x=60, y=180)
self.text=tkinter.Text(root)
self.text.place(y=220)
self.text.insert(tkinter.END,'This is just a test!')
def Send(self):
try:
host=self.entrySMTP.get()
port=int(self.entryPort.get())
user=self.entryUser.get()
pw=self.entryPass.get()
fromaddr=self.entryFrom.get()
toaddr=self.entryTo.get()
subject=self.entrySub.get()
text=self.text.get(1.0, tkinter.END)
msg=("From: %s\nTo: %s\nSubject: %s\n\n" % (fromaddr, toaddr, subject))
msg=msg+text
smtp=smtplib.SMTP(host, port)
smtp.set_debuglevel(1)
smtp.login(user,pw)
smtp.sendmail(fromaddr,toaddr,msg)
smtp.quit()
except Exception as e:
self.text.insert(tkinter.END, "\n发送错误\n")
root=tkinter.Tk()
window=Window(root)
root.minsize(600,480)
root.mainloop()