码迷,mamicode.com
首页 > 编程语言 > 详细

python学习之【16】网络编程

时间:2015-10-25 19:21:15      阅读:455      评论:0      收藏:0      [点我收藏+]

标签:

主题
  • 客户端/服务器架构
  • 套接字:通信终点
  • 套接字地址
  • 面向连接与无连接套接字
  • Python中的网络编程
  • SOCKET模块
  • 套接字对象方法
  • TCP/IP客户端和服务器
  • UDP/IP客户端和服务器
  • SocketServer模块
  • Twisted框架介绍
  • 相关模块

 

 
1.客户端服务器架构
 
     客户<---->INTERNET<------->服务器。客户连上一个预先已知的服务器,提出自己的请求,发送必要的数据,然后就等待服务器返回的数据。
 
2.套接字:通信终点
     套接字是一种具有"通信端点"概念的计算机网络数据结构。网络化的应用程序在开始任何通讯之前都需要创建套接字、就像电话插口一样,没有它就会完全没办法通信。Python只支持AF_UNIX,AF_NETLINK,AF_INET家族,由于我们只关心网络编程所以我们都只用AF_INET。
 
3.套接字地址
     如果把套接字比作电话接口----------即通信的最底层结构,那主机与端口就像区号与电话号码的一对组合。有了电话还不够,你还要知道你要打电话给谁,往哪打。一个因特网地址由网络通信所必须的主机和端口组成,而且另一端一定要有人听才可以。
     合法的端口号范围为0~65535,其中,小于1024的端口号为系统保留端口。
4.面向连接与无连接套接字
     (1)面向连接
               无论使用哪个地址家族,套接字的类型只有两种,面向连接和无连接。面向连接即是在通信前必须建立一条连接,就像跟朋友打电话一样。实现这种连接的主要协议就是传输控制协议(TCP),要创建TCP套接字就得在创建的时候指定套接字类型为SOCK_STREAM。TCP套接字采用SOCK_STREAM这个名字体现了它最为流套接字的特点,由于这些套接字使用网际协议(ip)来查找网络中的主机,所以这样形成的整个系统,一般会有两个协议(TCP和IP)名的组合来描述,即TCP/IP。
    (2)无连接
              即无需连接就可以进行通信。但这时,数据到达的顺序、可靠性及不重复性就无法保证了。数据是整个发送的,不会像面向连接的协议那样先被拆分成小块。
              实现这种连接的主要协议就是用户数据报协议(UDP)。要创建UDP套接字就得在创建的时候指定套接字类型为SOCK_DGRAM。"datagram"是"数据报"。
 
5.Python中的网络编程
     我们将使用Python中的socket模块,模块中的socket()函数用来创建套接字。要使用socket.socket()函数来创建套接字,语法如下:
     socket.socket(socket_family,socket_type,protocol=0)
     如前所述,Socket_family  不是 AF_VNIX 就是 AF_INET ,socket_type可以是SOCK_STREAM或是SOCK_DGRAM,protocol一般不填,默认为0。
6.SOCKET模块
     例如创建一个TCP/IP的套接字,你要这样调用socket.socket()函数:
     tcpSock = socket.socket(socket.AF_INET,socket.SOCKET_STREAM)
     
     UDP/IP的套接字
     udpSock = socket.socket(socket.AF_INET,socket.SOCKET_DGRAM)
由于socket模块中有太多的属性,我们在这里可以使用 “from module import *”的语句,我们就把socket模块里所有属性都带到我们的命名空间里了。
     tcpSock = socket(AF_INET,SOCKET_STREAM) 
 
7.套接字对象(内建)方法
            函数                       描述
        服务器端套接字函数
  •  s.bind( )                  绑定地址(主机名,端口号对)到套接字
  •  s.listen( )                 开始TCP监听
  •  s.accept( )               被动接受TCP客户端连接,(阻塞式)等待连接的到来。                    
       客户端套接字函数
  •  s.connect( )           主动初始化TCP服务器连接。
  •  s.connect_ex( )      connect( )扩展版本,出错时返回错误码,而不是抛出异常。
      公共用途的套接字函数
  •  s,recv( )                接受TCP数据。
  •  s.send( )               发送TCP数据。
  •  s.sendall( )            完整发送TCP数据。
  •  s.recvfrom( )        接受UDP数据。
  •  s.sendto( )           发送UDP数据。
  •  s.getpeername( )  连接到当前套接字的远程的地址(TCP连接)
  •  s.getsockname( )   当前套接字的地址。
  •  s.getsockopt( )     返回当前套接字的参数。
  •  s.setsockopt( )     设置指定套接字的参数。
  •  s.close( )              关闭套接字。
     面向模块的套接字函数
  •  s.setblocking( )    设置套接字的阻塞与非阻塞模式。
  •  s.settimeout( )     设置阻塞套接字操作的超时时间。
  •  s.gettimeout( )     得到阻塞套接字操作的超时时间。
     面向文件套接字函数
  •  s.fileno( )            套接字文件描述符。
  •  s.makefile( )        创建一个与该套接字关联的文件对象。
8.TCP/IP客户端和服务器
     TCP服务器设计伪代码:
     ss = socket()                    #创建服务器套接字
     ss.bind()                           #把地址绑定到套接字上
     ss.listen()                          #监听连接
     inf_loop:                           #服务器无线循环
          cs = ss.accept()           #接受客户端连接
     comm_loop:                     #通信循环
          cs.recv()/cs.send()       #对话(接收与发送)
     cs.close()                          #关闭客户端套接字
     ss.close()                           #关闭服务器套接字(可选)
 
  所有套接字都用socket.socket( )函数来创建。服务器需要"坐在某个端口上"等待请求。所以它们必须要"绑定"到一个本地的地址上。一个简单的(单线程)服务器会调用accept( )函数等待连接的到来。默认情况下,accept( )函数是阻塞式的,即程序在连接到来之前会处于挂起状态。套接字也支持非阻塞状态。
     TCP时间戳服务器(tsTserv.py)
创建一个能接受客户端的消息,在消息前加一个时间戳后返回TCP服务器
 
   
 from socket import *
     from time import ctime
     HOST = ‘‘
     PORT = 21567
     BUFSIZE = 1024
     ADDR = (HOST,PORT)
     
     tcpSerSock = socket(AF_INET,SOCK_STREAM)
     tcpSerSock.bind( ADDR)
     tcpSerSock.listen(5)
     
     while True:
          print ‘waiting for connection......‘
          tcpCliSock,addr = tcpSerSock.accept( )
          print ‘......connected from:‘,addr
          
          while True:
               data = tcpCliSock.recv(BUFSIZ)
               if not data:
                    break
               tcpCliSock.send(‘[%s]%s‘ %(ctime(),data))
               tcpCliSock.close( )
    tcpSerSock.close()

 

 
 
创建TCP客户端
     伪代码:
     cs = socket( )               #创建客户端套接字
     cs.connect( )                #尝试连接服务器
     comm_loop:
          cs.send( )/cs.recv( ) #对话(发送/接收)
     cs.close( )                    #关闭客户端套接字
 
TCP时间戳客户端(tsTclnt.py)
 
   
 1  from socket import *
 2  
 3      HOST = localhost
 4      PORT = 21567
 5      BUFSIZ = 1024
 6      ADDR = (HOST,PORT)
 7  
 8      tcpCliSock = socket(AF_INET,SOCK_STREAM)
 9      tcpCliSock.connect(ADDR)
10  
11      while True:
12           data = raw_input(>)
13           if not data:
14                break
15           tcpCliSock.send(data)
16           data = tcpCliSock.recv(BUFSIZ)
17           if not data:
18                break
19           print data
20  
21 tcpCliSock.close()

 

 
 
9.UDP/IP客户端和服务器
 
     UDP时间戳服务器(tsUserv.py)
 
    
 1 from socket import *
 2      from time import ctime
 3      
 4      HOST = ‘‘
 5      PORT = 21567
 6      BUFSIZ = 1024
 7      ADDR = (HOST,PORT)
 8  
 9      udpSerSock = socket(AF_INET,SOCK_DGRAM)
10      udpSerSock.bind(ADDR)
11  
12      while True:
13           print waiting for message......
14           data,addr = udpSerSock.recvfrom(BUFSIZ)
15           udpSerSock.sendto([%s] %s % (ctime,data) ,addr)
16           print ......received from and returned to:,addr
17  
18 udpSerSock.close()

 

 
 
创建一个UDP客户端
 
    
 1 from socket import *
 2      
 3      HOST = localhost
 4      PORT = "21567"
 5      BUFSIZ = 1024
 6      ADDR = (HOST,PORT)
 7  
 8      udpCliSock = socket(AF_INET,SOCK_DGRAM)
 9      
10      while Trus:
11           data = raw_input(>)
12           if not data:
13                break
14           udpCliSock.sendto(data,ADDR)
15           data,ADDR = udpCliSock.recvfrom(BUFSIZ)
16           if not data:
17                break
18           print data
19  
20 udpCliSock.close()

 

 
10.SocketServer模块
 
     SocketServer 是标准库中一个高级别的模块。用于简化实现网络客户端与服务器所需的大量样板代码。该模块中,已经实现了一些可供使用的类。
 
                                                                 SocketServer模块的类
 
描述
BaseServer 包含服务器核心功能与混合(mix-in)类挂钩;这个类只用于派生,所以不会生成这个类的实例;可以考虑使用TCPServer和UDPServer
TCPServer/UDPServer 基本的网络同步TCP/UDP服务器
UnixStreamServer/UnixDatagramServer 基本的基于文件同步TCP/UDP服务器
ForkingMixIn/ThreadingMixIn 实现了核心的进程化或线程化的功能;作为混合类,与服务器类一并使用以提供一些异步特性;这个类不会直接实例化。
ThreadingTCPServer/ThreadingUDPServer ThreadingMixIn和TCPServer/UDPServer的组合
BaseRequestHandler 包含处理服务器请求的核心功能,这个类只用于派生,所以不会生成这个类的实例可以考虑使用StreamRequestHandler 或 DatagramRequestHandler
StreamRequestHandler/DatagramRequestHandler 用于TCP/UDP服务器处理工具
   


创建一个SocketServerTCP服务器
 
在代码中,先导入我们的服务器类,然后像之前一样定义主机常量。主机常量后就是我们的请求处理器类,然后是启动代码。
 
 
例  SocketServer 时间戳TCP服务器(TsTservss.py)
     
   
 from SocketServer import (TCPServer as TCP,StreamRequsetHandler as SRH)
     from time import ctime
 
     HOST = ‘‘
     PORT = 21567
     ADDR = (HOST,PORT)
 
     class MyRequestHandler(SRH):
          def handle(self):
               print ......connected from:,self.client_address
               self.wfile.write([%s]%s % (ctime(),self.rfile.readline()))
     
     tcpServ = TCP(ADDR,MyRequestHandler)
     print waiting for connection...
     tcpServ.serve_forever( )
 

 


创建SocketServerTCP客户端
 
    
 1 from socket import *
 2      
 3      HOST = localhost
 4      PORT = 21567
 5      BUFSIZ = 1024
 6      ADDR = (HOST,PORT)
 7  
 8      while True:
 9           tcpCliSock = socket(AF_INET,SOCK_STREAM)
10           tcpCliSock.connect(ADDR)
11           data = raw_input(>)
12           if not data:
13                break
14           tcpCliSock.send(%s\r\n %data)
15           data = tcpCliSock.recv(BUFSIZ)
16           if not data:
17                break
18           print data.strip()
19           tcpCliSock.close()
20  

 

 
11.Twisted框架介绍
     Twsited是一个完全事件驱动的网络框架。它允许你使用和开发完全异步的网络应用程序和协议。需要安装它,系统中可以有:网络协议、线程、安全和认证、聊天/即时通讯、数据库管理、关系数据库集成、Web/internet、电子邮件、命令行参数、图形界面集成等。
 
 
创建一个Twisted Reactor TCP服务器
 
     Twsited Reactor事件戳服务器(tsTservTW.py)
 
     from twisted.internet import protocol,reactor
     from time import ctime
 
     PORT = 21567
     
     class TSServProtocol(protocol.Protocol)
 
-----------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
课后题
 
16-1.  套接字,面向连接与无连接有何区别?
答:socket第二个参数不同。面向连接即tcp通信函数为socket.socket(socket.AF_INET,socket.SOCK_STREAM),UDP通信函数第二个参数为SOCK_DGRAM。
16-2.  客户端/服务器架构。用你自己的语言描述这个架构。并给出几个例子?
答:服务器在某端口等待客户端的连接。怎么说呢      client<------------>internet<------------->server
16-3.  套接字。TCP和UDP中,哪一种服务器在接受连接后,把连接交给不同的套接字处理与客户端的通讯。
答:TCP。
16-4.  修改TCP(tsTclnt.py)和UDP(tsUclnt.py)客户端,让服务器的名字不要在代码里写死,要允许用户指定一个主机名和端口,只有在两个值都没有输入的时候才使用默认值。
答:修改后的tsTclnt.py
 1 from socket import *
 2 from time import ctime
 3 
 4 
 5 HOST = ‘‘
 6 PORT = 21567
 7 BUFSIZ = 1024
 8 ADDR = (HOST,PORT)
 9 
10 
11 tcpSerSock = socket(AF_INET,SOCK_STREAM)
12 tcpSerSock.bind(ADDR)
13 tcpSerSock.listen(5)
14 
15 
16 while True:
17         print waitiing for connection...
18         tcpCliSock,addr = tcpSerSock.accept()
19         print ...connected from:,addr
20 
21 
22         while True:
23                 data = tcpCliSock.recv(BUFSIZ)
24                 if not data:
25                         break
26                 tcpCliSock.send([%s] %s % (ctime(),data))
27 
28 tcpSerSock.close()
29  
30  

 

16-5.  网络互联和套接字。找到《python library reference》 示例tcp客户端/服务器程序,实现它并让它运行起来。先运行服务器,然后是客户端。http://www.python.org/doc/current/lib/Socket_Example.html
 
你认为这个服务器太无聊,决定要修改服务器,让它能识别以下命令:
 
data     服务器将返回它的当前时间,即time.ctime(time.time())
os        得到操作系统的信息(os.name)
ls         得到当前目录的文件列表
 
做这个作业的时候,你不一定要有网络------你的机器可以自己通讯。注:在服务器退出后,要清除绑定后才能再次运行,否则有可能得碰到‘端口已经被使用’的错误信息,操作系统一般会在5分钟内清除绑定。所以请耐心等待。
 
服务器端
 1 from socket import *
 2 import time,os
 3 
 4 
 5 HOST = ‘‘
 6 PORT = 21567
 7 BUFSIZ = 1024
 8 ADDR = (HOST,PORT)
 9 
10 
11 tcpSerSock = socket(AF_INET,SOCK_STREAM)
12 tcpSerSock.bind(ADDR)
13 tcpSerSock.listen(5)
14 
15 
16 while True:
17         print waitiing for connection...
18         tcpCliSock,addr = tcpSerSock.accept()
19         print ...connected from:,addr
20 
21         while True:
22                 data = tcpCliSock.recv(BUFSIZ)
23                 data = data.strip()
24                 if not data:
25                         break       
26                 if data == "date":
27                         tcpCliSock.send(%s % (time.ctime(time.time())))       
28                 elif data == "os":
29                         tcpCliSock.send(%s % (os.name))               
30                 elif data == "ls":
31                         tcpCliSock.send(%s % (os.listdir(os.curdir)))               
32                 else:
33                         tcpCliSock.send([%s] %s % (time.ctime(),data))
34                                        
35 
36 tcpSerSock.close()

 

 
16-6日期时间服务。使用socket.getservbyname()函数得到UDP协议中"daytime"服务所对应的端口。请参考getservbyname()函数的文档,查阅如何使用的详细语法。现在,写一个程序发送一个随便什么数据过去,等待回答。一旦你收到了服务器的信息,显示到屏幕上去。
答:服务端
 1 from socket import *
 2 from time import ctime
 3 
 4 
 5 HOST = "localhost"
 6 
 7 PORT = getservbyname("daytime","udp")
 8 
 9 BUFSIZ = 1024
10 
11 ADDR = (HOST,PORT)
12 
13 udpSerSock = socket(AF_INET,SOCK_DGRAM)
14 
15 udpSerSock.bind(ADDR)
16 
17 while True:
18     print "waiting for message..."
19     data,addr = udpSerSock.recvfrom(BUFSIZ)
20     udpSerSock.sendto("[%s]%s" % (ctime(), data),addr)
21     print "...received from and returned to:",addr
22 
23 
24 udpSerSock.close
25  

 

 
客户端
 1 from socket import *
 2 from time import ctime
 3 
 4 
 5 HOST = "localhost"
 6 PORT = getservbyname("daytime","udp")
 7 
 8 BUFSIZ = 1024
 9 
10 ADDR = (HOST,PORT)
11 
12 udpCliSock = socket(AF_INET,SOCK_DGRAM)
13 
14 
15 while True:
16     data = raw_input(">")
17     if not data:
18         break
19     udpCliSock.sendto(data,ADDR)
20     data,ADDR = udpCliSock.recvfrom(BUFSIZ)
21     if not data:
22         break
23     print data
24 
25 tcpCliSock.close()

 

 
16-7.半双工聊天。创建一个简单的半双工聊天程序。“半双工”的意思是当创建一个连接,服务启动的时候,只有一个人可以打字,另一个人只有在等到消息通知他输入消息时才能说话。一旦消息发送出去后,要等到有回复了才能发送下一条消息。一个人是服务端,另一个人是客户端。
 
客户端
from socket import *

HOST = "localhost"
PORT = 23346
BUFSIZ = 1024
ADDR = (HOST,PORT)


tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)


while True:
    data = raw_input("client>")
    if not data:
        continue
    tcpCliSock.send(data)
    while True:
        data = tcpCliSock.recv(BUFSIZ)
        if not data:
            continue
        else:
            print "server>",data
            break

tcpCliSock.close()

 

 
服务端
 1 from socket import *
 2 
 3 HOST = "localhost"
 4 PORT = 23346
 5 BUFSIZ = 1024
 6 ADDR = (HOST,PORT)
 7 
 8 
 9 tcpServSock = socket(AF_INET,SOCK_STREAM)
10 tcpServSock.bind(ADDR)
11 tcpServSock.listen(5)
12 
13 
14 
15 while True:
16     print "waiting for connection..."
17     tcpCliSock,addr = tcpServSock.accept()
18     print "connected from:",addr
19 
20     while True:
21         data = tcpCliSock.recv(BUFSIZ)
22         if not data:
23             continue
24         print "client>",data
25         data = raw_input("server>")
26         tcpCliSock.send(data)
27    
28 tcpServSock.close()
29  

 

---------------------------------------------------------------------
16-8 全双工聊天。修改你刚才的程序,改成全双工,即两个人可以独立地发送和接收消息。
答:
服务端
 1 #!/usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3 import socket,traceback,os
 4 from threading import *
 5 
 6 host = localhost
 7 port = 51423     #监听所有的接口
 8 
 9 #接受消息的线程
10 def handlerecv(clientsock):
11     print "New child",currentThread().getName()
12     print "Got connection from",clientsock.getpeername()
13     while True:
14         data = clientsock.recv(4096)
15         if not len(data):
16             break
17         print data
18     clientsock.close()
19 
20 #发送消息的线程
21 def handlesend(clientsock):
22     while True:
23         data = raw_input(">")
24         data = data + "\n";   #加上换行,好看一点。
25         clientsock.sendall(data)
26     #关闭连接
27     clientsock.close()
28 
29 #建立套接字
30 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
31 s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
32 s.bind((host,port))
33 s.listen(1)
34 
35 while True:
36     try:
37         clientsock,clientaddr = s.accept()
38     except KeyboardInterrupt:
39         raise
40     except:
41         traceback.print_exc()
42         continue
43 
44     t = Thread(target = handlerecv,args=[clientsock])
45     t.setDaemon(1)
46     t.start()
47 
48     r = Thread(target = handlesend,args=[clientsock])
49     r.setDaemon(1)
50     r.start()
51  
52  
53  
54  

 

客户端
 
 1 #!/usr/bin/env python
 2 #-*-coding:utf-8-*-
 3 
 4 from socket import *
 5 import sys
 6 from threading import *
 7 
 8 if(len(sys.argv) < 3):
 9     HOST = localhost
10     PORT = 51423
11 else:
12     HOST = sys.argv[1]
13     PORT = int(sys.argv[2])
14 
15 BUFSIZ = 1024
16 ADDR = (HOST,PORT)
17    
18 def handlesend(tcpCliSock):
19     while True:
20         sdata = raw_input(> )
21         if not sdata:
22             break
23         tcpCliSock.send(sdata)
24 
25     tcpCliSock.close()
26 
27 tcpCliSock = socket(AF_INET,SOCK_STREAM)
28 tcpCliSock.connect(ADDR)
29 
30 #建立发送消息的线程
31 s = Thread(target = handlesend,args=[tcpCliSock])
32 s.setDaemon(1)
33 s.start()
34 
35 while True:
36     rdata = tcpCliSock.recv(BUFSIZ)
37     if not rdata:
38         break
39     print rdata
40 tcpCliSock.close()

 

 
------------------------------------------------------------------
 
16-9  多用户全双工聊天。再次修改你的程序,把聊天服务改成支持多用户版本。
 
 
 

python学习之【16】网络编程

标签:

原文地址:http://www.cnblogs.com/elliottc/p/4909233.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!