Python 网络编程
1.客户端/服务器网络编程
在完成服务前,服务器必需先完成的设置:先创建一个通讯端点(套接字),让服务器能监听请求。
生活例子:服务器相当于公司总线电话,通讯端点相当于电话的插口,电话要通过插口才能与外界联系。
客户端的设置:只要创建一个通讯端点,建立到服务器的连接,然后客户端就可以提出请求了,请求可以包括数据交互,一旦请求处理完成,客户端收到了结果,通信就结束了。
2.面向连接与无连接
面向连接(TCP/IP):在通信前一定要建立一条连接,每一个要发送的信息可能会被查分成多份,到达目的地后按顺序拼接起来,传给正在等待的应用程序。顺序、可靠、不会重复
无连接(UDP/IP):无需建立连接就可以通讯,数据是整个发送,数据到达的顺序、可靠性及不重复性无法保证,没有要维持线路连接的额外负担。性能好、便宜。
3.套接字地址:addr=(host,port) 主机与端口
如把套接字比做电话的接口,那套接字地址的主机与端口就像区号与电话号码的一对组合。如电话0771-6518123 ,要打给谁(6518123),往哪打(0771)。
合法的端口号范围为0~65535,小于1024的为系统保留端口
4.socket
socket又称“套接字”,应用程序通常通过“套接字”向网络发出请求或者应答网络请求
socket.socket(socket_family,socket_type,protocal)
family:套接字家族可以是AF_UNIX或者AF_INET(指定IPV4家族)
type:套接字类型可以是SOCK_STREAM(面向连接)或SOCK_DGRAM(无连接)
protocal:一般不填默认为0
socket对象方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from socket import * 2 3 #服务器套接字 4 s.bind(addr) #将套接字与套接字地址绑定,在AF_INET下,以元组(host,port)的形式表示地址addr 5 s.listen(backlog) #开始TCP监听,backlog指定最大连接数,至少为1,大部分为5 6 s.accept() #被动接受TCP客户端连接,阻塞式等待连接的到来 7 8 #客户端套接字 9 s.connect(addr) #主动初始化与TCP服务器连接,以元组(host,port)的形式表示地址addr 10 11 #公共用途的套接字函数 12 s.recv(bufsize) #接收TCP数据,字符串返回,bufsize指定要接收的最大数据量 13 s.send(data) #发送TCP数据,将string中的数据发送到连接的套接字,返回发送的字节数 14 s.sendall(data) #完整发送TCP数据成功返None,失败则抛异常 15 s.close() #关闭套接字 16 s.recvfrom(bufsize) #接收UDP数据,返回(data,address)数据和发送数据的套接字地址 17 s.sendto(data,addr) #发送UDP数据,返回发送的字节数 18 s.getpeername() #返回连接套接字的远程地址,(ipaddr,port)ip地址和端口号 19 s.getsockname() #返回套接字自己的地址,(ipaddr,port)
5.TCP/IP
通用TCP服务器伪代码:
1 ss = socket() #创建服务器套接字 2 ss.bind() #把地址绑定到套接字上 3 ss.listen() #监听连接 4 inf_loop: #服务器无限循环 5 cs = ss.accept() #接收客户端连接 6 comm_loop: #通信循环 7 cs.recv()/cs.send() #对话(接收与发送) 8 cs.close() #关闭客户端套接字 9 ss.close() #关闭服务器套接字(可选)
创建一个服务器:能够接收客户端的消息,在消息前加一个时间戳后返回
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from socket import * 2 from time import ctime 3 4 def server(): 5 "接收客户端的消息,在消息前加一个时间戳后返回" 6 7 host = "localhost" #本地主机名 8 port = 9999 #端口号 9 bufsize = 1024 #设缓冲区大小为1K 10 addr = (host,port) #套接字地址 11 tcpSerSock = socket(AF_INET,SOCK_STREAM) #创建服务器套接字,IPV4面向连接 12 tcpSerSock.bind(addr) #绑定套接字地址 13 tcpSerSock.listen(5) #指定等待连接最大数 14 15 while True: #服务器无限循环 16 print("等待连接------------------->") 17 (tcpCliSock,addr) = tcpSerSock.accept() #接收客户端连接,返回客户端套接字和客户端套接字地址 18 print("连接来自:",addr) 19 20 while True: #通信循环 21 data = tcpCliSock.recv(bufsize) #接收客户端发来的数据 22 if not data: #如果没有数据了退出通信循环 23 break 24 tcpCliSock.send( ('[%s]%s' % (ctime(),data.decode('utf-8'))).encode('utf-8') ) #把要发送的数据全部编码 25 tcpCliSock.close() #关闭客户端套接字 26 27 if __name__=='__main__': 28 server()
通用TCP客户端伪代码:
1 cs = socket() #创建客户端套接字 2 cs.connect() #尝试连接服务器 3 comm_loop: #通信循环 4 cs.send()/cs.recv() #对话(发送和接收) 5 cs.close() #关闭客户端套接字(可选)
创建一个客户端:给服务器发送消息并接收消息
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from socket import * 2 3 def client(): 4 host = 'localhost' #本地主机名 5 port = 9999 #要与服务器端口一致 6 bufsize = 1024 #接收数据大小 1K 7 addr = (host,port) #客户端套接字地址 8 tcpCliSock = socket(AF_INET,SOCK_STREAM) #创建客户端套接字,IPV4面向连接 9 tcpCliSock.connect(addr) #连接服务器 10 11 while True: #通信循环 12 data = input('输入要发送的信息-->') #等待用户输入要发送的信息 13 if not data: #如果没有要发送的数据直接退出通信循环 14 break 15 tcpCliSock.send(data.encode('utf-8')) #发送信息 16 data = tcpCliSock.recv(bufsize) #接收服务器返回的消息 17 if not data: #如果没有数据了退出通信循环 18 break 19 print(data.decode('utf-8')) 20 tcpCliSock.close() #关闭客户端套接字 21 22 if __name__=='__main__': 23 client()
服务器端:
客户端:
6.UDP/IP
通用UDP/IP服务器伪代码:
1 ss = socket() #创建服务器套接字 2 ss.bind() #绑定服务器套接字地址 3 inf_loop: #服务器无限循环 4 cs = ss.recvfrom()/ss.sendto() #对话 5 ss.close() #可选 关闭服务器套接字
服务器:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from socket import * 2 from time import ctime 3 4 def udpServer(): 5 "接收客户端的消息,在消息前加一个时间戳后返回" 6 host = 'localhost' 7 port = 8888 8 bufsize = 1024 #接收数据大小 1K 9 addr = (host,port) #服务器套接字地址 10 udpSerSock = socket(AF_INET,SOCK_DGRAM) #创建服务器套接字,IPV4无连接 11 udpSerSock.bind(addr) #绑定套接字地址 12 13 while True: #服务器无限循环 14 print('等待消息------------>') 15 (data,addr) = udpSerSock.recvfrom(bufsize) #接收数据 16 data.decode('utf-8') #对接收的数据解码 17 udpSerSock.sendto( ('[%s]%s' % (ctime(),data)).encode('utf-8') ,addr) #对数据进行编码再发送 18 print('收到来自(%s)的消息并返回' % (addr,)) 19 20 if __name__=='__main__': 21 udpServer()
通用UDP/IP客户端伪代码:
1 cs = socket() #创建客户端套接字 2 comm_loop: #通信循环 3 cs.sendto()/cs.recvfrom() #对话 4 cs.close #关闭套接字
客户端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from socket import * 2 3 def udpClient(): 4 host = 'localhost' 5 port = 8888 #必须与服务器一致 6 bufsize = 1024 #接收数据大小 1K 7 addr = (host,port) #套接字地址 8 udpCliSock = socket(AF_INET,SOCK_DGRAM) #IPV4无连接 9 10 while True: #通信循环 11 data = input('输入要发生的信息--------->') 12 if not data: #没有信息则退出通信循环 13 break 14 udpCliSock.sendto(data.encode('utf-8'),addr) #向服务器发送数据 15 (data,addr) = udpCliSock.recvfrom(bufsize) #接收服务器发来的数据 16 if not data: #没有数据则退出循环 17 break 18 print(data.decode('utf-8')) 19 udpCliSock.close() 20 21 if __name__=='__main__': 22 udpClient() 23
服务器:
客户端:
7.文件传输协议(FTP)
工作流程:
1.客户端连接远程的FTP服务器
2.客户端输入用户名和密码(或“匿名”和电子邮件地址)
3.客户端做各种文件传输和信息查询操作
4.客户端退出远程FTP服务器,结束通讯
因特网上的FTP客/服模式都使用两个套接字来通讯:一个是控制和指令端口(21号端口)发送FTP协议,而数据通过数据端口(有时是20号端口)传输。
说有时是因为FTP有两种模式:主动和被动。只有在主动模式,服务器才使用数据端口,服务器主动连接客户端的数据端口。在被动中,服务器告诉客户端随机端口号,由客户端主动建立数据连接。
使用FTP:需导入ftplib模块,并实例化一个ftplib.FTP类对象,所有的FTP操作都要使用这个对象来完成
ftplib.FTP类方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 login(user='',passwd='',acct='') #登陆到FTP服务器,所有参数可选 2 pwd() #得到当前工作目录 3 cwd(path) #把当前工作目录设置为path 4 dir([path[,cb]]) #显示path目录里的内容,cb可选是一个回调函数 5 nlst([path]) #与dir()类似,但返回一个文件名的列表,而不是显示这些文件名 6 retrlines(cmd,[,cb]) #给定FTP命令,用于下载文本文件,可选cb处理文件每一行 7 retrbinary(cmd,cb[,bs=8192]) #用于下载二进制文件,每一块8K(8192=8*1024) 8 storlines(cmd,f) #上传文本文件,要给定一个文件对象f 9 storbinary(cmd,f[,bs=8192]) #上传二进制文件,文件块大小默认8K 10 rename(old,new) #把远程文件old改名new 11 delete(path) #删除位于path的远程文件 12 mkd(directory) #创建远程文件 13 rmd(directory) #删除远程目录 14 quit() #关闭连接并退出
8.网络新闻传输协议(NNTP)
供用户在新闻组中下载或发表帖子的方法
1.连接到服务器
2.登陆(可选,根据NNTP服务器的配置)
3.发送请求
4.退出
一般来说,在登陆完成后,要调用group()方法来选择一个感兴趣的新闻组。方法返回服务器的返回信息、文章的数量、第一个和最后一个文章的ID和组的名字。有了这些信息后,就可做一些操作,如看文章、下载帖子或发表文章
nntplib.NNTP类