python成长之路【第九篇】:网络编程

一、套接字

1.1、套接字
套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个程序(又名一个进程)与另一个运行的程序进行通信。这就是所谓的进程间通信(Inter Process Communication,IPC)。有两种类型的套接字:基于文件的和面向网络的。

第一种:基于文件的
  因为两个进程运行在同一台计算机上,所以这些套接字都是基于文件的,这意味着文件系统支持他们的底层基础结构。这是能够说的通的,因为文件系统是一个运行在同一个主机上的多个进程之间的共享常量。
第二种:基于网络的
  基于网络的套接字,有自己的家族名字AF_INET,或者地址家族:因特网

地址家族(address family,缩写AF)

1.2、面向连接和无连接的套接字
面向连接的通信提供序列化的、可靠的和不重复的数据交付,而没有记录边界。这基本上意味着每条消息可以拆分成多个片段,并且每一条消息片段都确保能够到达目的地,然后将他们按顺序组合在一起,最后将完整消息传递给正在等待的应用程序。
实现这种连接类型的主要协议是传输控制协议(TCP)。为了创建TCP套接字,必须使用SOCK_STREAM作为套接字类型。

实现无连接的主要协议是用户数据报协议(UDP)。为了创建UDP套接字,必须使用SOCK_DGRAM作为套接字类型。

二、Python中的网络编程

2.1、socket()模块函数
要创建一个套接字,必须使用socket.socket()函数,它一般的语法如下。
  socket(socket_family, socket_type, protocol=0)
所以,为了创建TCP/IP套接字,可以用下面的方式调用socket.socket()。
  tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
同样,为了创建UDP/IP套接字,需要执行以下语句。
  udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

参数一:地址簇socket_family
  socket.AF_INET #IPv4(默认)
  socket.AF_INET6 #IPv6
  socket.AF_UNIX #只能够用于单一的unix系统进程间通信
参数二:类型socket_type
  socket.SOCK_STREAM #流式socket,for TCP(默认)
  socket.SOCK_DGRAM #数据报式socket,for UDP
  socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文,此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
  socket.SOCK_RDM #是一种可靠的UDP形式,即保证交互数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
  socket.SOCK_SEQPACKET #可靠的连续数据包服务
参数三:协议
  protocol通常省略,默认为0,则系统就会根据地址格式和套接类别,自动选择一个合适的协议。

因为有很多socket模块属性,如果使用“from socket import *”,那么他们就把socket属性引入到了命名空间中。虽然看起来麻烦,但是通过这种方式将能够大大缩短代码。
  tcpSock = socket(AF_INET, SOCK_STREAM)
一旦有了一个套接字对象,那么使用套接字对象的方法将可以进行进一步的交互。

2.2、套接字对象(内置)方法
常见的套接字对象方法和属性

2.3、创建通用TCP服务器的一般伪代码
伪代码:服务端
  ss = socket() #创建服务器套接字
  ss.bind() #套接字与地址绑定
  ss.listen() #监听连接
  inf_loop: #服务器无限循环
    cs = ss.accept() #接收客户端连接,产生阻塞
    comm_loop: #通信循环
      cs.recv()/cs.send() #对话(接收/发送)
    cs.close() #关闭客户端套接字
  ss.close() #关闭服务器套接字 #可选

伪代码:客户端
  cs = socket() #创建客户端套接字
  cs.connect() #尝试连接服务器
  comm_loop: #通信循环
    cs.send()/cs.recv() #对话(发送/接收)
  cs.close()

from socket import *
from time import ctime

HOST = ‘‘
PORT = 9999
BUFSIZ = 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(bytes(ctime(), encoding="utf-8") + data)
    tcpCliSock.close()
tcpSerSock.close()
解释:
第1个代码块:
	导入了time.ctime()和socket模块的所有属性。

第2个代码块:
	HOST变量时空白的,这是对bind()方法的标识,表示它可以使用任何可用的地址。我们也选择了一个随机的端口号。将缓冲区大小设置为1KB。可以根据网络性能和程需要改变这个容量。listen()方法的参数是在连接被转接或拒绝之前,传入连接请求的最大数。

第3个代码块:
	分配了TCP服务器套接字(tcpSerSock),紧随其后的是将套接字绑定到服务器地址以及开启TCP监听器的调用。

第4个代码块:
	一旦进入服务器的无限循环之后,我们就(被动地)等待客户端的连接。当一个连接请求出现时,我们进入对话循环中,在该循环中我们等待客户端发送的消息。如果消息是空白的,这意味着客户端已经退出,所以此时我们将跳出对话循环,关闭当前客户端连接,然后等待另一个客户端连接。如果确实得到了客户端发送的消息,就将其格式化并返回相同的数据,但是会在这些数据中加上当前时间戳的前缀。最后一行永远不会执行,它只是用来提醒读者,如果写了一个处理程序来考虑一个更加优雅的退出方式,那么应该调用close()方法。
from socket import *

HOST = ‘127.0.0.1‘  #or ‘localhost‘
PORT = 9999
BUFSIZ = 1024
ADDR = (HOST, PORT)

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

while True:
    data = input(‘>>:‘)
    if not data:
        break
    tcpCliSock.send(bytes(data, ‘utf-8‘))
    data = tcpCliSock.recv(BUFSIZ)
    if not data:
        break
    print(str(data, encoding="utf-8"))    #和下面语句相同
    # print(data.decode(‘utf-8‘))
tcpCliSock.close()
解释:
第1个代码块:
	从socket模块导入所有属性
第2个代码块:
	HOST和PORT变量指服务器的主机名与端口名。因为在同一台计算机上运行测试,所以HOST包含本地主机名。端口号PORT应该与你为服务器设置的完全相同。此外,也将缓冲区大小设置为1KB。
第3个代码块:
	分配了TCP客户端套接字,接着主动调用并连接到服务器。
第4个代码块:
	客户端也有一个无限循环,但这并不意味着它会像服务器的循环一样永远运行下去。客户端循环在以下两种条件下将会跳出:用户没有输入,或者服务器终止且对recv()方法的调用失败。否则,在正常情况下,用户输入一些字符串数据,把这些数据发送到服务器进行处理。然后,客户端接收到加了时间戳的字符串,并显示在屏幕上。
执行上面代码输出结果:
	>>:i
	Tue Sep 13 19:11:20 2016i
时间: 2024-10-14 16:41:18

python成长之路【第九篇】:网络编程的相关文章

Python成长之路第二篇(1)_数据类型内置函数用法

数据类型内置函数用法int 关于内置方法是非常的多这里呢做了一下总结 (1)__abs__(...)返回x的绝对值 #返回x的绝对值!!!都是双下划线 x.__abs__() <==> abs(x) 例如: #!/usr/bin/python print "abs(-45) : ", abs(-45) print "abs(100.12) : ", abs(100.12) print "abs(119L) : ", abs(119L)

Python成长之路第一篇(1)__字符串初识

在很多编程的书中都会以print  "Hello,world!"这样的而一个程序为开始,那么hello,world是什么呢?这就是本章讲解的字符串(也即是一串字符) 一.单引号,双引号和转义引号 (1)在一般的时候 'Hello,world!'和"Hello,world!"是没有什么区别的,那么为什么会两个都可以用呢?是因为在某些情况下,他们会排上用处 1 >>> "Hellow,world" 2 'Hellow,world' 

python成长之路第一篇(5)文件的基本操作

一.三元运算 我们在上章学习的if,,else,,有一种简便的方法 他的表达式是这样的:变量 = 值1 if 条件 else 值2 解释过来就是如果aaa等于sss则输出值1否则输出值2 二.类的概念 类是面向对象编程的核心, 它扮演相关数据及逻辑的容器角色.它们提供了创建"真实"        对象(也就是实例)的蓝图.对于Python,一切事物都是对象,对象基于类创建. 如何查询对象的类呢? 为啥分为有下划线和没下划线的呢,这些又是什么呢?本例中以查看的是列表的类,那么这个类下面就

Python成长之路第一篇(4)_if,for,while条件语句

有了以上的基本基础,已经上面写的几个小练习,大家肯定有很多的不满,比如查询为什么查询一次就退出了呢?下面我们来学习条件语句 一.万恶的加号 以前我们在print的时候如果要加上变量都有是使用+来作为连接,但是这样做是不好的 因为在使用加号的时候,会在内存中开辟新的内存地址来存放新的内容这样做的坏处就是增加了内存的消耗 那么我们该怎么办呢? (1)字符串格式化 ①内置占位符 Python 支持格式化字符串的输出 .尽管这样可能会用到非常复杂的表达式,但最基本的用法是将一个值插入到一个有字符串格式符

Python成长之路 第一篇 《Python基础》

1.python文件命名 - 后缀名可以是任意的,但为规范便于识别,后缀名应为 .py 2.两种执行方式    python解释器   py文件路径     python   进入解释器: 实时输入并获取到执行结果 3.解释器路径 在Linux系统中应添加  #!/user/bin/env python    , windows系统中可不添加 4.编码 # -*- coding:utf8 -*-  (在python3中可不加,python只要出现中文头部必须加) ascill  只能编译英文 u

Python成长之路第一篇(2)-初识列表和元组

可以将列表和元组当成普通的"数组",他能保存任意数量任意类型的Python对象,和数组一样都是通过数字0索引访问元素,列表和元组可以存储不同类型的对象,列表和元组有几处重要区别.列表元素用([])包括,元素的个数和值可以改变,而元组用({})包括,不能更改.元组可以看成是只读的列表 一.初识列表 1.下面是一个正常的列表 >>> lis = ['xiaoyuan',25] 在序列中,可以包含其他的序列,也就是列表可以包含列表元组等 >>> lis =

Python成长之路第二篇(2)_列表元组内置函数用法

列表元组内置函数用法list 元组的用法和列表相似就不一一介绍了 1)def append(self, p_object):将值添加到列表的最后 # real signature unknown; restored from __doc__ """ L.append(object) -- append object to end """ pass (2)def count(self, value): 值的出现次数 # real signature

Python成长之路第二篇(3)_字典的置函数用法

字典的置函数用法(字典dict字典中的key不可以重复) class dict(object): """ dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d =

python成长之路第二篇(4)_collections系列

一.分别取出大于66的数字和小于66的数字 小练习:需求要求有一个列表列表中存着一组数字,要求将大于66的数字和小于66的数字分别取出来 aa = [11,22,33,44,55,66,77,88,99,90] dic = {} for i in aa :     ifi <= 66 :         if 'k1' in dic.keys():             dic['k1'].append(i)         else:             #创建只有一项元素的列表    

Python学习之路:socket网络编程

参考链接:http://www.cnblogs.com/alex3714/articles/5830365.html 动态导入模块 1 *动态导入模块代码 2 3 4 #from lib import "aa" 5 #import lib 6 lib = __import__('lib.aa') 7 print(lib) 8 obj = lib.aa.C() 9 print(obj.name) 10 11 #官方建议使用方法 12 import importlib 13 aa = im