Python 网络编程

第1章        客户/服务器网络介绍

1.       一个gopher的客户端。

2.       socketmakefile

3.       一个简单的服务器,socket.setsockopt() socket.bind(host,port), socket.listen(1), socket.accept()

 

第2章        网络客户端

1.    使用socket对象

# -*- coding: cp936 -*-

import socket

#创建socket对象

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#连接

s.connect(('www.cainiao8.com',80))

#获取信息

print 'getsockname(): ' , s.getsockname()

print 'getpeername():' , s.getpeername()

 

其中socket.AF_INETIPV4的协议族。TCP对应SOCK_STREAM, UDP对应SOCK_DGRAM

 

2.    根据服务名称获取端口号码

 

>>> socket.getservbyname('http')

80

 

3.    socket的异常处理

socket可能抛出4种异常:errotgaierrorherrortimeout。在写操作之后最好使用shutdown()来确保真的没有异常发生。第2章的shutdown.py例程介绍了异常的捕获。shutdownfile.py介绍了使用makefile()之后使用文件方式使用socket时候对异常的捕获,异常仍然是socket.error,作者建议尽量不要在使用文件方式的时候用缓冲器。

4.    UDP

使用UDP的主要区别:

l  socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

l  可以不用connect,直接 s.sendto(‘’, (host, port))

详见第2章的udp.pyudptime.py

 

 

 

3 网络服务器

1. 建立服务器的步骤:

1)       建立socket对象

2)       设置socket选项

cockopts.py文件可以列出当前系统下Python支持的socket选项。

import socket

solist = [x for x in dir(socket) if x.startswith('SO_')]

solist.sort()

for x in solist:

    print x

在调试程序的时候,最常用的是将SO_REUSEADDR设置为True,代表在程序进程结束后立即释放进程占用的端口。

3)       绑定端口

例如绑定80端口,bind的第一个参数是IP地址:

s.bind(‘’,80)

4)       侦听连接

s.listen(5)

表示允许的队列中等待的连接数。

 

2. 接受连接

basicserver.py是一个简单的服务器,在收到连接的时候简单的print一条信息,并且将连接关闭。主要源代码如下:

host = ''                               # Bind to all interfaces

port = 51423

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind((host, port))

s.listen(1)

while 1:

    clientsock, clientaddr = s.accept()

    print "Got connection from", clientsock.getpeername()

    clientsock.close()

Windows下使用IDLE运行会造成IDLE假死,直接双击运行没问题。如下图:

 

 

服务器

 

 

 

 

3.    异常处理

考虑到服务器的容错能力,errorserver.py使用了各种try将程序包围起来。

4.    UDP

不需要listen。大致代码如下:

while 1:

    try:

        message, address = s.recvfrom(8192)

        s.sendto(message, address)

5.    inetdxinetd

像写普通Python程序一样写服务器。

6.    syslog

记录信息,Windows没有syslog

7.    避免死锁

使用一个客户端和服务器端的例子来说明一种死锁的可能情况。客户端试图向服务器发送一个大数据,而服务器每次读取一部分数据后给客户端发送一个回应,但是由于客户端的设计是在发送完之后才进行读取,因此服务器发送的回应被缓存。如此一来,缓存逐渐达到系统极限。服务器端由于缓存不足而无法再发送,卡在sendall一处,客户端试图发送数据,但是服务器端卡了,无法进行recv,所以客户端也卡在这里,形成死锁。

 

4 域名系统

1.        执行基本的DNS查询

使用socket模块的getaddrinfo()函数,它返回一个元组的列表。

>>> import socket

>>> res = socket.getaddrinfo('google.com',None)

>>> print res

[(2, 0, 0, '', ('74.125.127.100', 0)), (2, 0, 0, '', ('74.125.67.100', 0)), (2, 0, 0, '', ('74.125.45.100', 0))]

2.        反向查找

使用socket模块的gethostbyaddr

>>> import socket

>>> res = socket.getaddrinfo('google.com',None)

>>> res

[(2, 0, 0, '', ('74.125.67.100', 0)), (2, 0, 0, '', ('74.125.45.100', 0)), (2, 0, 0, '', ('74.125.127.100', 0))]

>>> res = socket.gethostbyaddr('74.125.67.100')

>>> res

('gw-in-f100.google.com', [], ['74.125.67.100'])

 

反向查找的结果可能是对方IP刻意伪造的,gethostbyaddr-paranoid.py在反向查找之后再进行正向的查找,可以确保信息的正确性。

 

书后面介绍了利用PyDNS进行高级的DNS查找功能,搞了老半天,不过没安装成功。

5 高级网络操作

1. 半开放socket

只可以发送或者接收的socketshutdown(0)表示禁止将来读,shutdown(1)表示禁止将来写,2表示禁止读和写。01的效果可以累加。

2. 超时

timeoutserver.py演示了超时的用法,调用settimeout方法,主要代码如下:

#建立socket,绑定到端口

while 1:

    try:

        clientsock, clientaddr = s.accept()

……

    clientsock.settimeout(5)

如果客户端在限定时间之内没有发送内容,连接就会被服务器断开。

3. 广播

接收端需要设置socket广播选项:

s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

发送方除了设置那以上选项外,sendTo的参数不再使用IP地址,而是使用'<broadcast>'

4. poll

避免在socket上的I/O将程序阻塞。pollclient.py介绍了poll的使用方法:

……

#ppoll对象。

p = select.poll()

#注册到感兴趣的socket上。

p.register(s.fileno(), select.POLLIN | select.POLLERR | select.POLLHUP)

while 1:

         #50毫秒返回一次,如果没有结果就返回空列表。

    results = p.poll()

    if len(results):

        if results[0][1] == select.POLLIN:

            data = s.recv(4096)

            if not len(data):

                print("/rRemote end closed connection; exiting.")

                break

            # Only one item in here -- if there's anything, it's for us.

            sys.stdout.write("/rReceived: " + data)

            sys.stdout.flush()

        else:

            print "/rProblem occured; exiting."

            sys.exit(0)

#50毫秒要执行的操作。

spin()

 

原文地址:https://www.cnblogs.com/lhj588/p/2521696.html