Python入门系列(十)——网络

目录:
一、TCP编程
二、UDP编程

Python 提供了两个级别访问的网络服务:
低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。SocketServer其实是在Socket基础上的一个多线程升级,作为入门教程,我们不做涉及。

我们在此将socket编程方式分为面向连接的方式(即TCP)和不面向连接的方式(即UDP)进行分别讨论。

一、TCP编程

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,对应到编程中,它的特点就是需要先建立连接,再进行数据传输。
在此盗一张很棒的图解方便大家理解:


盗图

然后,临时为了演示需要,将一个日历查看功能布在了服务端,可通过接受客户端提交的请求,返回对应的请求内容。当然,你完全可以根据自己的需要布置更加有意义的小程序替换这里,如:nmap等。

需要注意的是,socket在python3中的数据传输均使用bytes的方式,所以我们需要及时的进行编码解码操作。

其中socket的基本语法为socket.socket([family[, type[, proto]]])

family: 套接字家族可以使AF_UNIX或者AF_INET
type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM或SOCK_DGRAM
protocol: 一般不填默认为0
作为入门系列我们不在这些概念上拓展,具体用法参见以下完整实例:
#TCP服务端
import socket
import calendar

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip_port=('127.0.0.1',11111)      #定义绑定ip和端口
s.bind(ip_port)                  #绑定监听
s.listen(5)                      #最大连接数
while True:
    print('正在等待客户端连接……')
    conn,addr=s.accept()         #接收连接请求
    print("接入地址: %s" % str(addr))
    msg='连接成功!\n【欢迎来到史上最辣鸡的日历系统】\n输入"exit"退出本系统'
    conn.send(msg.encode())      #发送应答信息
    while True:                  #持续接收数据
        data=conn.recv(1024)
        if data==b'exit':        #收到exit断开连接
            break
        try:
            conn.send(calendar.month(2019, int(str(data.decode()))).encode())
        except IndexError:       #异常处理机制,防止用户乱输造成服务端崩溃
            pass
            conn.send('请正确输入月份:(1-12)'.encode())
    conn.close()                 #断开连接

#输出
正在等待客户端连接……
接入地址: ('127.0.0.1', 16942)
正在等待客户端连接……
#TCP客户端
import socket

c=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip_port=('127.0.0.1',11111)     #定义访问ip和端口
c.connect(ip_port)              #连接服务器

while True:
    data = c.recv(1024)  # 接收返回信息
    print(data.decode())
    msg=input('请输入想要查看的月份: 例如:1\n>>>>>')
    c.send(msg.encode())
    if msg=='exit':             #用户输入exit时退出
        break

c.close()                       #断开连接

#输出:
连接成功!
【欢迎来到史上最辣鸡的日历系统】
输入"exit"退出本系统
请输入想要查看的月份: 例如:1
>>>>>1
    January 2019
Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

请输入想要查看的月份: 例如:1
>>>>>2
   February 2019
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28

请输入想要查看的月份: 例如:1
>>>>>1111
请正确输入月份:(1-12)
请输入想要查看的月份: 例如:1
>>>>>exit

Process finished with exit code 0

其中有一处类型转换是使用的int(str()),即bytes类型解码转字符串再转数字的形式,暂时没有找到更有效且稳定的替换方案,在线求助各位大佬~

关于常用套接字函数在上面的例子中已通过注释的形式进行了说明,在此进行统一整理:

#服务器端套接字
s.bind()
绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。
s.listen()
开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
s.accept()
被动接受TCP客户端连接,(阻塞式)等待连接的到来

#客户端套接字
s.connect()
主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
s.connect_ex()
connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

#公共用途的套接字函数
s.recv()
接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。
s.send()
发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。
s.sendall()
完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
s.recvfrom()
接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
s.sendto()
发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。
s.close()
关闭套接字
s.getpeername()
返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
s.getsockname()
返回套接字自己的地址。通常是一个元组(ipaddr,port)
s.setsockopt(level,optname,value)
设置给定套接字选项的值。
s.getsockopt(level,optname[.buflen])
返回套接字选项的值。
s.settimeout(timeout)
设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
s.gettimeout()
返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
s.fileno()
返回套接字的文件描述符。
s.setblocking(flag)
如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。
s.makefile()
创建一个与该套接字相关连的文件

二、UDP编程

UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。对应到编程中,就是不需要连接的建立,直接进行数据传输。
我们直接改写上面的例子进行对比讲解:

#服务端
import socket
import calendar

s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_port=('127.0.0.1',22222)      #定义绑定ip和端口
s.bind(ip_port)                  #绑定监听
while True:
    print('UDP服务端监听开启……\n')
    data,addr = s.recvfrom(1024) #recvfrom()获取数据和地址
    if data==b'exit':
        break
    print('Received from %s:%s.' % addr)
    try:                         #异常处理机制,防止用户乱输造成服务端崩溃
        s.sendto(calendar.month(2019, int(str(data.decode()))).encode(),addr)
    except:
        s.sendto('请正确输入月份:(1-12)'.encode(),addr)
s.close()

#输出:
UDP服务端监听开启……

Received from 127.0.0.1:61716.
UDP服务端监听开启……

Received from 127.0.0.1:61716.
UDP服务端监听开启……

Received from 127.0.0.1:61716.
UDP服务端监听开启……
#客户端
import socket

c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_port = ('127.0.0.1', 22222)  #定义访问ip和端口
print('【欢迎来到史上最辣鸡的日历系统】\n输入"exit"退出本系统')
while True:
    msg=input('请输入想要查看的月份: 例如:1\n>>>>>')
    if msg=='exit':
        break
    c.sendto(msg.encode(), ip_port)
    data=c.recv(1024)           #接收服务器返回数据
    print(data.decode())
c.close()                       #断开连接

#输出:
【欢迎来到史上最辣鸡的日历系统】
输入"exit"退出本系统
请输入想要查看的月份: 例如:1
>>>>>1
    January 2019
Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

请输入想要查看的月份: 例如:1
>>>>>2
   February 2019
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28

请输入想要查看的月份: 例如:1
>>>>>11111
请正确输入月份:(1-12)
请输入想要查看的月份: 例如:1
>>>>>exit

Process finished with exit code 0

简单说下区别,UDP编程,服务端不需要创建连接等待,直接接收;也不需要listen设置最大连接数。客户端同样不需要先创建连接,也就是不需要进行connect()操作,直接发送数据即可。数据发送方式改为sendto(),需要制定地址,毕竟UDP是非面向连接的。

TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据。相对TCP,UDP则是面向无连接的协议。使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • 网络编程 一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运...
    go以恒阅读 2,005评论 0 6
  • 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编...
    程序员欧阳阅读 2,012评论 1 37
  • 个人认为,Goodboy1881先生的TCP /IP 协议详解学习博客系列博客是一部非常精彩的学习笔记,这虽然只是...
    贰零壹柒_fc10阅读 5,052评论 0 8
  • 1、TCP为什么需要3次握手,4次断开? “三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端...
    杰伦哎呦哎呦阅读 3,475评论 0 6
  • 1. 网络概述 1.1 概述 1.1.1什么是网络? 早期的计算机都是互相独立的一套一台以数据运算为主的机器。...
    _宁采臣阅读 719评论 0 1