网络编程
网络编程预备知识
网络模型
OSI模型:7层
应用层、会话层、表示层 、传输层、网络层、数据链路层、物理层。
TCP/IP模型:4层
应用层、传输层、网络层、数据链路层。
TCP/IP模型
应用层:网络应用程序
传输层:负责数据的传输,将数据封装成某种格式
TCP协议: 传输控制协议(Transmission Control Protocol)
基于连接的网络传输协议
稳定的可靠的无重复的网络传输协议
UDP协议:用户数据报协议(User Datagram Protocol)
一种不可靠的网络传输协议
网络层(IP层):数据的包装
数据链路层:MAC地址
TCP/UDP
TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
TCP协议
在使用TCP协议的进行数据传输的时候,客户端需要先和服务端建立连接。
连接的建立:三次/三路握手。

TCP的特点:基于连接的 可靠的 稳定的 无重复的。
又要保证数据的完整性 又要保证传输速度快,怎么解决?
使用UDP协议!
IP地址的分类
IPV4 IP地址分为5类
IP地址的组成:32bit组成(4Bytes)
IP地址的表达方式:点分十进制(192.168.1.100)
IP地址的构成:网路号 + 主机号
A类 0 网络号(7) 主机号(24) 0.0.0.0 ~ 127.255.255.255
B类 10 网络号(14) 主机号(16) 128.0.0.0 ~ 191.255.255.255
C类 110 网络号(21) 主机号(8) 192.0.0.0 ~ 223.255.255.255
D类 1110 网络号(28) 多播组号
E类
PORT/DNS/ARP
端口号 PORT:标识一个网络应用程序
占16bit,2Bytes
思考:端口号能够表示的最大的正整数:65535
DNS:DomainNameSystem 域名系统
域名:用一串有一定规则/寓意的字符串来标识某一台服务器(具体的IP地址)。
ARP:Address Resolution Protocol 地址解析协议
作用:客户端向某个IP地址所代表的服务器发起ARP请求,对应的服务器返回 自己的MAC地址
典型应用:ping命令
子网掩码
子网掩码:通过子网掩码的值和IP地址的值进行按位与运算,得到这个IP地址所对用的网络号。
举例:
-IP: 192.168.10.100
-Mask: 255.255.255.0
-网络号:192.168.10. 0
笔试题:假设A的IP地址为192.168.10.100, B的IP地址为192.168.11.100,请问用何办法能够使A和B进行网络通信?
将两台计算机的子网掩码设置为:255.255.0.0
TCP编程
Socket
什么是 Socket?
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
import socket
构造一个socket
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
family: 协议簇 AF_INET:对于IPV4协议的TCP或者UDP
AF_INET6:对于IPV6
type:协议类型 SOCK_STREAM表示使用TCP协议
SOCK_DGRAM表示使用UDP协议
TCP服务端编程流程
1、构造一个socket对象
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
2、绑定服务器的IP地址以及端口号
s.bind(('192.168.31.251', 6666))
3、监听绑定的端口,允许同时等待连接的请求的最大数目为10
s.listen(10)
4、阻塞接收客户端的请求
cli, addr = s.accept()
cli: 成功连接服务器的客户端的socket对象
addr:成功连接服务器的客户端的ip和port所组成tuple
5、阻塞接收客户端发送的数据
data = cli.recv(1024)
注意:data的数据类型不是str而是bytes
import socket import threading def data_hanle(*args): cli = args[0] addr = args[1] while True: try: # 阻塞接收客户端发送的数据,每次接收最多1024个字节 data = cli.recv(1024) # print(data)、 # 将bytes类型的数据转换为str tmp = str(data, encoding='utf8') print("{} send: {}".format(addr, tmp)) except: return None if __name__ == "__main__": #构造socket对象 #使用tcp协议 s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) #绑定IP地址及端口号 host = socket.gethostname() s.bind((host, 8888)) #s.bind(('192.168.31.251', 8889)) #s.bind(('127.0.0.1', 8888)) #监听 s.listen(10) while True: cli, addr = s.accept() print("new connection: {}".format(addr)) #创建一个线程来接收cli所发送的数据 t = threading.Thread(target=data_hanle, args=(cli, addr)) t.start()
TCP服务端编程注意事项:
1、当客户端自动退出以后,服务端recv到的数据长度为0
2、如果客户端被强制关闭,服务端会抛出“ConnectionResetError”异常
TCP客户端编程
1、构造一个socket对象
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
2、连接服务器
s.connect(('192.168.31.251', 8888))
3、发送数据
s.send(b'hello world')
import socket import time if __name__ == "__main__": #构造socket对象 #使用tcp协议 s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) while True: try: #连接服务器 s.connect(('192.168.142.1', 8888)) #s.send(b'hello world') data = "hello world" #将str转换为bytes类型 tmp = bytes(data, encoding='utf8') while True: s.send(tmp) time.sleep(1) break except: continue while True: pass
Socket 对象(内建)方法
| 函数 | 描述 |
|---|---|
| 服务器端套接字 | |
| 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() | 创建一个与该套接字相关连的文件 |
Python Internet 模块
以下列出了 Python 网络编程的一些重要模块:
| 协议 | 功能用处 | 端口号 | Python 模块 |
|---|---|---|---|
| HTTP | 网页访问 | 80 | httplib, urllib, xmlrpclib |
| NNTP | 阅读和张贴新闻文章,俗称为"帖子" | 119 | nntplib |
| FTP | 文件传输 | 20 | ftplib, urllib |
| SMTP | 发送邮件 | 25 | smtplib |
| POP3 | 接收邮件 | 110 | poplib |
| IMAP4 | 获取邮件 | 143 | imaplib |
| Telnet | 命令行 | 23 | telnetlib |
| Gopher | 信息查找 | 70 | gopherlib, urllib |
更多内容可以参阅官网的 Python Socket Library and Modules。

浙公网安备 33010602011771号