一、套接字
套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象。它们允许程序接受并进行连接,如发送和接受数据。为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要。
套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳。许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持。
三种最流行的套接字类型是:stream,datagram和raw。stream和datagram套接字可以直接与TCP协议进行接口,而raw套接字则接口到IP协议。但套接字并不限于TCP/IP。
二、套接字模块
套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问。使用该模块可以实现客户机和服务器套接字。要在python中建立具有TCP和流套接字的简单服务器,需要使用socket模块。利用该模块包含的函数和类定义,可生成通过网络通信的程序。一般来说,建立服务器连接需要六个步骤。
第1步是创建socket对象。调用socket构造函数。
socket=socket.socket(familly,type)
要创建一个套接字,你必须使用socket.socket()函数,它在socket模块,其中有一般的语法:
s = socket.socket (socket_family, socket_type, protocol=0)
下面是参数的描述:
-
socket_family: 这是AF_UNIX或AF_INET,正如我刚才解释.
-
socket_type: 这是SOCK_STREAM,或为SOCK_DGRAM.
-
protocol: 这通常被不用关心,默认为0.
第2步则是将socket绑定(指派)到指定地址上,socket.bind(address)
address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。
第3步,绑定后,必须准备好套接字,以便接受连接请求。
socket.listen(backlog)
backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。
第4步,服务器套接字通过socket的accept方法等待客户请求一个连接:
connection,address=socket.accept()
调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有俩个元素的元组,形如(connection,address)。第一个元素(connection)是新的socket对象,服务器通过它与客户通信;第二个元素(address)是客户的internet地址。
第5步是处理阶段,服务器和客户通过send和recv方法通信(传输数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。recv方法在接受数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接受端。以后调用recv时,多余的数据会从缓冲区删除。
第6步,传输结束,服务器调用socket的close方法以关闭连接。
建立一个简单客户连接则需要4个步骤。
第1步,创建一个socket以连接服务器 socket=socket.socket(family,type)
第2步,使用socket的connect方法连接服务器 socket.connect((host,port))
第3步,客户和服务器通过send和recv方法通信。
第4步,结束后,客户通过调用socket的close方法来关闭连接。
实例:
这是Socket Server 部分:
import socket
s = socket.socket()
host = socket.gethostname()
port = 8088
s.bind((host,port))
s.listen(5)
while True:
c, addr = s.accept()
print 'Got connection from', addr
c.send('Thank you for connection')
c.close()
这是Socket Client 部分:
import socket
s = socket.socket()
host = socket.gethostname()
port = 8088
s.connect((host,port))
print s.recv(1024)
运行时,请将对应的端口(这里是8088)添加到防火墙的InBound和OutBound的规则中。
1.2 urllib 和 urllib2 模块
urllib
和 urllib2
是Python标准库中最强的的网络工作库。通过这两个库所提供的上层接口,使我们可以像读取本地文件一样读取网络上的文件。而且 urllib2
并不是 urllib
的升级版本(应该是一种补充),二者是不可相互替代的。
通过使用 urllib
的 urlopen
函数可以很容易的打开远程的文件,如下:
from urllib import urlopen
webpage = urlopen('http://www.cnblogs.com/IPrograming/')
txt = webpage.readline(45)
print txt # !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
也可以通过在通过在路径的前面添加 file:
来访问本地文件:
from urllib import urlopen
webpage = urlopen(r'file:D:\H\sr23upd\ADD_ABBR.txt')
txt = webpage.readline(45)
print txt
如果你还可以通过 urllib
提供的 urlretrieve
函数,来直接保存远程文件副本:
from urllib import urlretrieve
webpage = urlretrieve('http://www.cnblogs.com/IPrograming/','C:\\temp.html')
print type(webpage) # <type 'tuple'>
1.3 其他与网络相关的模块
除了 socket、urllib和urllib2这些模块以外标准库还有很多和网络相关的模块,下面的列表是其中的一部分:
===========================================================
模块 描述
===========================================================
asynchat asyncore的增强版本
asyncore 异步socket处理程序
cgi 基本的CGI支持
Cookie Cookie对象操作,主要用于服务器操作
cookielib 客户端cookie支持
email E-mail消息支持(包括MIME)
ftplib FTP客户端模块
gopherlib gopher客户端博客
httplib HTTP客户端模块
imaplib IMAP4客户端模块
mailbox 读取几种邮件的格式
mailcap 通过mailcap文件访问MIME配置
mhlib 访问MH邮箱
nntplib NNTP客户端模块
poplib POP客户端模块
robotparser 支持解析Web服务器的robot文件
SimpleXMLRPCServer 一个简单的XML-RPC服务器
stmpd SMTP服务器模块
smtplib SMTP客户端模块
telnetlib Telnet客户端模块
urlparse 支持解析URL
xmlrpclib XML-RPC的客户端支持
Python网络模块
可以使用Python中的网络/互联网编程的一些重要的模块列表.
Protocol | Common function | Port No | Python module |
---|---|---|---|
HTTP | Web pages | 80 | httplib, urllib, xmlrpclib |
NNTP | Usenet news | 119 | nntplib |
FTP | File transfers | 20 | ftplib, urllib |
SMTP | Sending email | 25 | smtplib |
POP3 | Fetching email | 110 | poplib |
IMAP4 | Fetching email | 143 | imaplib |
Telnet | Command lines | 23 | telnetlib |
Gopher | Document transfers | 70 | gopherlib, urllib |
请查看上面提到所有库的合作与FTP,SMTP的POP,IMAP协议.
最后:
1、建立socket
建立socket对象需要搞清通信类型和协议家族。通信类型指明了用什么协议来传输数据。协议的例子包括IPv4、IPv6、IPX\SPX、AFP。对于internet通信,通信类型基本上都是AF_INET(和IPv4对应)。协议家族一般表示TCP通信的SOCK_STREAM或者表示UDP通信的SOCK_DGRAM。因此对于TCP通信,建立一个socket连接的语句为:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
对于UDP通信,建立一个socket连接的语句为:
s=socket.socket(socket.AF_INET,SOCK_DGRAM)
2、连接socket
连接socket需要提供一个tuple,包括host(主机名或者IP)和port(远程端口),类似代码为:
s.connect(("www.baidu.com",80)
3、寻找端口号
socket库中利用getservbyname()函数可以查询端口号,一般需要两个参数:一是协议名,如http、smtp、pop3等,一个是端口名,如tcp、udp
例如:
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
port=socket.getservbyname('http','tcp')
port的返回值为80。若改为:
port=socket.getservbyname('smtp','tcp')
port的返回值为25。
4、从socket获取信息
建立socket连接后,可以通过getsockname()获取本身的ip地址和端口号,也可以通过getpeername()显示远程机器的ip地址和端口号。
如:在python shell中
>>> import socket
>>> s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> port=socket.getservbyname('http','tcp')
>>> s.connect(('www.baidu.com',port))
>>> print s.getsockname()
('192.168.87.138', 3213)
>>> print s.getpeername()
('220.181.111.147', 80)
Socket 模块的类方法
类方法 说明
Socket 低层网络接口(每个 BSD API)
socket.socket(family, type) 创建并返回一个新的 socket 对象
socket.getfqdn(name) 将使用点号分隔的 IP 地址字符串转换成一个完整的域名
socket.gethostbyname(hostname) 将主机名解析为一个使用点号分隔的 IP 地址字符串
socket.fromfd(fd, family, type) 从现有的文件描述符创建一个 socket 对象
Socket 模块的实例方法
实例方法 说明
sock.bind( (adrs, port) ) 将 socket 绑定到一个地址和端口上
sock.accept() 返回一个客户机 socket(带有客户机端的地址信息)
sock.listen(backlog) 将 socket 设置成监听模式,能够监听 backlog 外来的连接请求
sock.connect( (adrs, port) ) 将 socket 连接到定义的主机和端口上
sock.recv( buflen[, flags] ) 从 socket 中接收数据,最多 buflen 个字符
sock.recvfrom( buflen[, flags] ) 从 socket 中接收数据,最多 buflen 个字符,同时返回数据来源的远程主机和端口号
sock.send( data[, flags] ) 通过 socket 发送数据
sock.sendto( data[, flags], addr ) 通过 socket 发送数据
sock.close() 关闭 socket
sock.getsockopt( lvl, optname ) 获得指定 socket 选项的值
sock.setsockopt( lvl, optname, val ) 设置指定 socket 选项的值
举例:
>>> import socket
>>> socket.gethostbyname('www.baidu.com')
'220.181.111.147'
>>> socket.gethostbyname('www.126.com')
'123.125.50.22'
>>> socket.getfqdn('123.125.50.22')
'123.125.50.22'
这里getfqdn却不能返回域名?
5、处理错误
关于错误异常的处理,主要就是用try、except语句。如将python网络编程学习笔记(1)中gopherclient.py进行一下修改:
# -*- coding: cp936 -*-
##modify by 小五义
import socket,sys
port =70
host=sys.argv[1]
filename=sys.argv[2]
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
except Socket.error,e:
print "建立socket错误:%s"%e
try:
s.connect((host,port))
except socket.gaierror,e:
print "host或者端口错误:%s" %e
except socket.error,e:
print "连接错误:%s" %e
try:
s.sendall(filename+"\r\n")
except socket.error,e:
print "数据发送错误:%s" %e
sys.exit(1)
while 1:
try:
buf=s.recv(2048)
except socket.error,e:
print "接收错误:%s"%e
sys.exit(1)
if 'does not exist' in buf:
print "%s文件不存在" %filename
else:
if not len(buf):
break
sys.stdout.write(buf)
参考文献:
http://www.jb51.net/article/50857.htm
http://www.cnblogs.com/IPrograming/p/Python-socket.html
http://blog.csdn.net/alpha5/article/details/24122749
http://www.cppblog.com/lai3d/archive/2008/02/19/42919.html
http://www.showerlee.com/archives/1051