--------------------------------------------------------------------------
#一个停止并等待输入或输出的程序成为被阻塞的程序
#死锁问题,在每次发送数据时接收端都接受一次,避免数据积压
--------------------------------------------------------------------------
基本客户端操作
--------------------------------------------------------------------------
#文件对象类型:read()、write()、readline()、readlines(),[↓阻塞与非阻塞]
#send()[TCP]、sendall()[TCP]、sendto()[UDP]、recv()[TCP]、recvfrom()[UDP]
#一旦结束写操作,应该立刻调用shutdown()函数,强制清除缓存里面的内容
--------------------------------------------------------------------------
#通信类型AF_INET(IPv4),协议簇SOCK_STREAM(TCP),SOCK_DGRAM(UDP)
s
= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立SOCKET
s.connect(('quux.org', 70))
#连接服务器及端口
s.sendall("/ \r\n")
#发送全部数据
s.send("/ \r\n")
#发送数据(可循环)
buf = s.recv(2048)
#接收数据(可循环)
--------------------------------------------------------------------------
文件类对象
--------------------------------------------------------------------------
#对于makefile()指定缓冲器需要使用flush()清理缓冲内容
#对于makefile()返回的对象并不提供一个对shutdown()的调用
s
= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立SOCKET
s.connect(('quux.org', 70))
#连接服务器及端口
fd = s.makefile('rw',0)
#创建文件类型(模式,缓存)0为不关闭缓存模式
fd.write("/
\r\n") #向文件类对象写入(可循环)
buf = fd.readlines()
#从文件类对象读取(可循环)
--------------------------------------------------------------------------
基本服务器操作(Server)
--------------------------------------------------------------------------
#s.bind(('',
80))函数第一个参数通常为空,标识绑定到所有的接口和地址
s =
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1) #设置成可复用的
s.bind((‘’, 51423))
#主机设置为空可以接受来自任意地方的连接,并设置端口
s.listen(1)
#开始等候来自客户端的连接,每次最多只有一个等候处理
while 1:
#↓s.accept()返回一个新连接客户端的socket和客户端IP
clientsock, clientaddr = s.accept()
clientfile = clientsock.makefile('rw',0) #创建文件类型,读写,关缓存
clientfile.write("Welcome, " + str(clientaddr) + "\n") #发数据
clientfile.write("Pleass enter a string:") #发数据
line =
clientfile.readline().strip() #收数据
clientfile.write("You entered %d characters.\n" % len(line)) #发数据
clientfile.close() #关闭
clientsock.close()
#关闭
--------------------------------------------------------------------------
高级接口
--------------------------------------------------------------------------
f
= gopherlib.send_selector(file, host) #建立socket和连接[f.readlines()]
f =
urllib.urlopen('http://%s%s' % (host, file))
#f.read()下载
--------------------------------------------------------------------------
寻找端口号(/etc/services)
->
从socket获取信息
--------------------------------------------------------------------------
port
= socket.getservbyname('http', 'tcp') #寻找TCP(UDP)的HTTP协议端口号
s.connetc(("www.google.com", port))
#通过寻找到的端口号连接
print "Connected from", s.getsockname()
#显示本身的IP地址和端口号
print "Connected to", s.getpeername()
#显示服务器的IP地址和端口号
--------------------------------------------------------------------------
使用UDP(Client)
--------------------------------------------------------------------------
s
= socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
port =
socket.getservbyname('http','udp')
s.connect((host,
port))
s.sendall(data)
buf =
s.recv(2048)
--------------------------------------------------------------------------
有时使用UDP可以根本不调用connect()
--------------------------------------------------------------------------
s
= socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
host =
socket.gethostbyname('time.nist.gov') #获取IP地址
s.sendto('',
(host, port)) #调用sendto向服务器发送一个空字符串
buf = s.recvform(2048)
#返回(touple)内容为接收的数据和发送数据的机器地址
--------------------------------------------------------------------------
使用UDP(Server)
--------------------------------------------------------------------------
s
=
socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
s.bind((host, port))
#
message, address = s.recvfrom(8192)
#接收数据(可循环)
s.sendto(message, address)
#发送数据(可循环)
--------------------------------------------------------------------------
连接UDP(Server)的(Client)
--------------------------------------------------------------------------
s
= socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
s.sendto('aaaa',("192.168.35.139", 51423))
s.recvfrom(2048)
--------------------------------------------------------------------------
设置和得到socket选项
--------------------------------------------------------------------------
#通常服务器会在进程终止后保留几分钟该程序端口,防止超时使用该端口
s.socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
#SO_REUSEADDR
标记为true,系统会在服务器socet被关闭后马上释放该服务器端口
s.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1) #设置
s.getsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
#查看
--------------------------------------------------------------------------
SO_BINDTODEVICE
SO_BROADCAST
SO_DONTROUTE
SO_KEEPALIVE
SO_OOBINLINE
SO_REUSEADDR
SO_TYPE
--------------------------------------------------------------------------
通过syslog来记录日志
--------------------------------------------------------------------------
#syslog模块在开始记录信息前需要调用openlog()函数来初始化syslog接口
openlog(标识符信息(例如进程名称,ID等)[,
选项[, 工具]])
syslog.openlog("%s[%d]" %
(os.path.basename(),os.getpid(),0,syslog.LOG_DAEMON)
--------------------------------------------------------------------------
#LOG_CONS
访问不到机器的syslog进程或记录信息错误时,在系统控制台显示该信息
#LOG_NDELAY
不进行任何延时就打开syslog程序的连接
#LOG_NOWAIT 在系统上建立一个新的进程来记录信息
#LOG_PID
自动在每条日志信息中包含进程ID
#LOG_PERROR
错误除了记录到syslog中,还会在stderr打印出来
--------------------------------------------------------------------------
#LOG_AUTH
认证信息:登录,退出
#LOG_CRON 来自自动命令日程安排程序的信息
#LOG_DAEMON
任何不能被归纳如日志种类的系统服务器信息
#LOG_KERN 操作系统的核心信息
#LOG_LOGCALx
从LOG_LOCAL0到LOG_LOCAL7为本地使用,由管理员定制
#LOG_LPR 打印服务器信息
#LOG_MAIL
和邮件有关的信息
#LOG_NEWS Usernet新闻信息
#LOG_USER
用户定义的普通且非特殊的信息
#LOG_UUCP UNIX-to-UNIX Copy
Protocol(UUCP)信息
--------------------------------------------------------------------------
↑(初始化完毕)现在可以实际记录一条信息
--------------------------------------------------------------------------
syslog([重要性,]
message)
syslog.syslog(syslog.LOG_ERR,"System Error")
#LOG_EMERG
紧急情况,整个系统非正常关机或不能使用
#LOG_ALERT 向管理员发出警报;需要立即采取措施
#LOG_CRIT
一个知名的错误已经发生
#LOG_ERR 一个普通错误发生
#LOG_WARNING 一条警告被记录
#LOG_NOTICE
对于一个重要的正常情况的通知
#LOG_INFO 普通信息
#LOG_DEBUG
调试信息;通常被丢弃
--------------------------------------------------------------------------
域名系统(DNS)
->正向查找
------------------------------------------------
#getaddrinfo(地址,端口[,家族[,类型[,原始[,标记]]]])
#返回tuple:(家族,
类型, 原始, 标准名, 地址)
#正向查找捕获异常错误为:socket.gaierror
socket.getaddrinfo("域名",None)
↓不显示重复
socket.getaddrinfo("域名",None,0,socket.SOCK_STRAM)
------------------------------------------------
socket.gethostbyname()
#域名解析,不支持IPv6
------------------------------------------------
域名系统(DNS)
->反向查找
------------------------------------------------
#确保为每个反向查找的行为捕获和处理socket.herror
------------------------------------------------
try:
socket.gethostbyaddr("IP地址")
except socket.herror, e:
"Couldn't look up name:",
e
------------------------------------------------
域名系统(DNS)
->对反向查找数据真实性检查
------------------------------------------------
x =
socket.gethostbyaddr("IP地址")[0]
f =
socket.getaddrinfo(x,None,0,socket.SOCK_STREAM)
if not IP地址 in f: print
"Error
IPaddress"
------------------------------------------------
域名系统(DNS)
->获得环境信息
------------------------------------------------
socket.gethostname()
#获取系统本地主机名
socket.getfqdn()
#获取主机名并试图取完整数据
------------------------------------------------
使用PyDNS库的DNS模块
------------------------------------------------
#查找系统配置的DNS,Linux:resolv.conf,Win:注册表
DNS.DiscoverNameServers()
#也可以手动指定DNS地址
DNS.defaults['server']=['202.106.0.20','8.8.8.8']
------------------------------------------------
#建立一个请求对象,通过该对象发出任何DNS查询请求
find
=
DNS.Request()
#请求对象的req()方法用来执行实际查询
#参数:name:给出实际查询的名称
#参数:qtype,制订了前面列表中的某条record类型
info=find.req(name='baidu.com',qtype=DNS.Type.ANY)
#↑应答对象有个属性叫answers,其中包含所有返回的应答列表
info.answers
------------------------------------------------
半开放socket
------------------------------------------------
socket.shutdown(参数)
#参数
0 表示禁止将来读
#参数 1 表示禁止将来写
#参数 2
标识禁止将来读写
#对参数的设置是累积的,先0后1相当于2
------------------------------------------------
Socket超时
------------------------------------------------
#如果超过了设置时间,则产生:socket.timeout异常
clientk, clientr = s.accept()
clientk.settimeout(15)
#超过10秒无操作则超时断开
------------------------------------------------
字符串结束标识符:
------------------------------------------------
#发送字符串之前先发送一个位移的字符串结束标识
#待字符串发送完成后,发送字符串结束标识
#或者发送字符串之前先发送一个要发送字符串的大小
------------------------------------------------
理解网络字节顺序
------------------------------------------------
#在网络上发送整型数据的时候,通常有两种选择:
#一个ASCII码的字符串,接收方需要解析;
#一个二进制字,一般是16或32位长;
------------------------------------------------
#struct模块支持数据在Python和二进制质检的转换
#主要使用两种格式:H(16位整数),I(32位整数)
#struct.pack(接收整型),struct.unpack(接收字符串)
------------------------------------------------
x
= struct.pack('!H',len('test')) #长度转化!H
y = struct.pack('!I',len('test'))
#长度转化!I
m = struct.unpack('!H','test')[0] #字符转化!H
z =
struct.unpack('!I','test')[0] #字符转化!I
struct.pack('!H',m)
#转化回来!H
struct.pack('!I',z)
#转化回来!I
------------------------------------------------
使用广播数据
->Server
------------------------------------------------
s =
socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#↓开启广播功能,将具备接收和处理广播和非广播数据的能力
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
s.bind((host,
port))
message, address = s.recvfrom(8192)
s.sendto('I am here',
address)
------------------------------------------------
使用广播数据
->Client
------------------------------------------------
dest =
('',51423)
s = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
s.sendto("hello",dest)
(buf,address)
=
s.recvfrom(2048)
------------------------------------------------
绑定到特殊的地址
------------------------------------------------
host
= '127.0.0.1' #则127.0.0.1为绑定到的地址
port =
51423
------------------------------------------------
使用poll()或select()实现时间通知
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------