一.TCP流式套接字的应用
1.HTTP网页传输
1)HTTP协议:超文本传输协议,属于应用层协议,应用层协议可以选择传输层服务。
HTTP协议选用的传输层协议是TCP
HTTP协议应用:网页的获取,基于网站的数据传输;也被用作基于HTTP的数据传输
特点:
①应用层协议,传输层使用tcp传输
②简单灵活,和多种语言对接方便
③无状态协议,不记录用户的通信内容
④成熟稳定'http1.1'
工作模式:
①使用HTTP双方均遵循HTTP协议规定发送,接收消息体
②请求方根据协议组织请求内容发送给对方
③服务方,收到内容,按照协议解析
④请求方,收到回复,根据协议解析
2) HTTP请求格式:
请求行 请求头 空行 请求体
①请求行
请求种类 请求内容 协议版本
GET / HTTP/1.1
'请求种类':
GET : 获取网络资源
POST :提交一定的附加数据,得到返回结果
HEAD :获取响应头
PUT : 更新服务器资源
DELETE :删除服务器资源
CONNECT :预留
TRACE :测试
OPTIONS :获取服务器性能
'请求内容:'
浏览器地址栏中IP:端口'/'及'/'之后的内容
备注:浏览器地址栏回车的请求类型:GET
②请求头
以键值对的形式对请求信息进行描述;本阶段学习均采用浏览器自动填充的形式
③请求体
提交具体的请求参数
3) HTTP响应格式:
响应行 响应头 空行 响应体
②响应行:
版本信息 响应码 附加信息
HTTP/1.1 200 OK
响应码:
1xx 请求已接收,正在处理
2xx 请求响应成功
3xx 重定向,完成任务需要其他操作
4xx 客户端错误
5xx 服务端错误
200 成功
401 没有访问权限
404 请求页面不存在
500 服务器发生未知错误
503 服务器暂时无法执行(可能因为网络原因或者并发量太大导致)
③响应头:
以键值对的形式对响应信息进行具体描述
④响应体:
将客户想要的内容进行返回
代码示例:运行程序,浏览器地址栏输入:127.0.0.1:8000像服务端发起请求;若不存在index.html文件,则触发IOError异常。
'''一个简易的http服务端程序
①响应浏览器http请求
②无论请求什么内容,都响应一个固定的静态页面
注意点:
①connfd.getpeername()获取客户端的IP及端口
②定义响应内容时,响应行,响应头,空行,响应体,用'\r\n'分隔每行内容
③请求字符串可以用splitlines()方法,获得请求行,请求头,空行,请求体组成的列表
'''
import socket
def handle_client(connfd):
'''处理浏览器请求,并返回响应内容'''
print("Connect to",connfd.getpeername())
request = connfd.recv(4028).decode()
requestHeaders = request.splitlines()
for line in requestHeaders:
# 打印请求行,请求头,空行及请求体
print(line)
try:
f = open('index.html')
except IOError:
response = 'HTTP/1.1 404 not found\r\n' # 响应行
response += '\r\n' # 空行,响应头选用默认值
response += '******Sorry the page is not found******' #响应体
else:
response = 'HTTP/1.1 200 OK\r\n' # 响应行
response += '\r\n' # 空行,响应头选用默认值
# 文件流对象属于可迭代对象,同时也是迭代器
for i in f:
response += i #响应体
finally:
connfd.send(response.encode())
connfd.close()
def main():
sockfd = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sockfd.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
ADDR = ("0.0.0.0",8000)
sockfd.bind(ADDR)
sockfd.listen(5)
while True:
print("Waiting for connection...")
connfd,addr = sockfd.accept()
#拿到connfd新的套接字后,则立刻交由相应的函数处理浏览器请求
handle_client(connfd)
sockfd.close()
if __name__ == '__main__':
main()
2.文件传输
1)服务端
'''文件服务器,发送文件给客户端'''
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 便于调试,设置套接字属性在服务端退出后,短时间恢复,端口可以立即被重用
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
ADDR = ("127.0.0.1",8888)
s.bind(ADDR)
s.listen(5)
while True:
print("Waiting for connected...")
connfd,addr = s.accept()
print("Connect to",addr)
# 由客户端指定要下载的文件
file = connfd.recv(1024)
with open(file,'rb') as f:
while True:
# 循环读取文件内容并发送
data = f.read(1024)
if not data:
break
connfd.send(data) #以二进制形式打开文件,读取的也是字节流
connfd.close()
s.close()
2)客户端
'''实现从服务器下载文件'''
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ADDR = ("127.0.0.1",8888)
# 向服务端发起连接请求
s.connect(ADDR)
# 输入服务端文件
src_file = input("Enter the file name you need:")
# 输入下载保存路径+文件名
des_file = input("Save to file as ?")
if des_file == '':
des_file = '自定义一个路径' + src_file
else:
des_file = '自定义一个路径' + des_file
s.send(src_file.encode())
with open(des_file,'wb') as des:
while True:
# 循环接收文件内容,并写入客户端文件
data = s.recv(1024)
if not data:
break
des.write(data)
s.close()
二.UDP数据报套接字的应用
局域网内发送和接收广播消息
1)发送端
'''发送广播消息的目标IP
sendto--->***.***.***.255
'''
import socket
from time import sleep
# 创建数据报套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 设置套接字属性:允许接收和发送广播消息
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
ADDR = ("广播地址",8888)
while True:
try:
data = b"This is a broadcast news!"
# 发送广播消息
s.sendto(data,ADDR)
sleep(2)
except KeyboardInterrupt:
# Ctrl + C退出
print("停止广播")
break
s.close()
2)接收端
'''需要能够接收局域网内所有主机的广播消息
绑定IP为"0.0.0.0"
'''
import socket
# 创建数据报套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 设置套接字属性:允许接收和发送广播消息
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
# 作为接收方,需要绑定IP地址
ADDR = ("0.0.0.0",8888)
s.bind(ADDR)
while True:
try:
# 接收广播消息
data,addr = s.recvfrom(1024)
print("Receive {} from {}".format(data.decode(),addr))
except KeyboardInterrupt:
# Ctrl + C退出
print('停止接收广播消息!')
break
except Exception as e:
print(e)
s.close()