目录

  1. 网络收发缓冲区
  2. TCP粘包
  3. UDP服务端编程
  4. UDP客户端编程
  5. TCP与UDP编程区别
  6. 套接字对象
  7. UDP应用之广播
  8. TCP应用之HTTP服务

1. 网络收发缓冲区

套接字传输注意事项
 1.监听套接字存在客户端即可发起连接
 		但是最终连接的处理需要accept处理
 2.如果连接的另外一端退出
 		则 recv会立即返回空字符串并解除阻塞
 3.当连接的另一端退出是,再试图 .send 发送
 		就会产生BrokenPipeError
 	
 网络的收发缓冲区 :
 	发送(send)--->发送缓冲--(操作系统)-->接受缓冲--->接受(recv)
 缓冲区作用 : 协调收发(处理)速度 ; 减少交互次数
 send 和 recv 实际上是和缓冲区进行交互,发送缓冲区满时就无法发送
 	接受缓冲区满时recv才阻塞

2. TCP粘包

产生原因 :
	TCP套接字以字节流方式传输,没有消息边界
	发送和接受并不能保证每次发送都及时的被接受
影响 : 如果每次发送内容表达一个独立的含义
	此时可能需要处理粘包防止产生歧义
处理方法 :
	1.每次发送的消息添加结尾标志(人为增加消息边界)
	2. 发送数据结构体
	3. 协调收发速度,每次发送后都预留接收时间,不适合大量使用(0.1s)

3. UDP服务端编程

socket ---> bind ---> recvfrom ---> sendto
			      个--------------------|
1.创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)

2.绑定地址
sockfd.bind(addr)

3.消息收发
data , addr = sockfd.recvfrom(buffersize)
功能 : 接受UDP消息
参数 : 每次最多接受多大的消息
返回值 : data 接收到的数据 / addr 消息发送端的地址
*一次接受一个数据报,如果数据报大小大于buffersize则会丢失部分消息

sockfd.sendto(data , addr)
功能 : 发送UDP消息
参数 : data 发送的消息 (bytes格式)
		addr 目标地址
返回值 : 发送的字节数

4. 关闭套接字
sockfd.close()
#udp_server.py
from socket import *


#创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)

#绑定地址
sockfd.bind(('0.0.0.0',8888))


#收发消息
while True:
    data = connfd.recvfrom(1024)

    print("Receive from %s:%s" % (addr,data.decode()))
    connfd.sendto(b'Receive your message',addr)

#关闭套接字   
sockfd.close()

4. UDP客户端编程

1.创建套接字
socket(AF_INET,SOCK_DGRAM)
2.消息收发
recvfrom / sendto
3.关闭套接字
close()

注 : sys.argv : 获取命令行参数,得到一个列表
import sys
print(sys.argv)
命令本身是 argv[0]
后面的参数从argv[1]开始,默认以空格分隔
使用引号引起来的内容算作一个整体
命令行参数都以字符串放入列表

5. TCP与UDP编程区别

TCP套接字
UDP套接字
1. 流式套接字使用字节流的方式传输
	数据报套接字以数据报形式传输数据
2.TCP会有粘包现象,UDP有消息边界不会粘包
3.TCP可以保证数据传输完整性,UDP则不保证
4.TCP需要进行listen/accept操作,UDP不需要
5.TCP收发消息使用新的套接字,recv send
	UDP使用 recvfrom sendto
	
补充函数
sendall()函数
功能 : 发送TCP消息
参数 : 要发送的内容,bytes格式
返回值 : 成功返回 None 失败产生异常

6. 套接字对象

套接字对象的属性
import socket
dir(socket)
s = socket()
#设置客户端断开,端口立即释放
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
#获取设置选项值 >>> value = 1
s.getsockopt(SOL_SOCKET,SO_REUSEADDR)

s.bind(('192.168.0.1',8888))
s.listen(1024)
c,addr = s.accept()
print(c.getpeername())

属性名

作用

s.family

获取套接字地址族类型 >>> INET …

s.type

获取套接字的类型 >>>SOCK_STREAM / SOCK_DGRAM …

s.getsockname()

获取套接字的绑定地址 >>>(‘192.168.0.1’,8888)

s.fileno()

获取套接字的文件描述符 >>>每一个I/O事件,操作系统都会分配一个不同的自然数作为编号,该正整数即为此I/O的文件描述符(stdin ~1;stdout ~ 2;stuerr ~ 3)

s.getpeername()

获取客户端连接套接字的对应地址

s.setsockopt(level,option,value)

设置套接字选项,丰富或者修改套接字属性功能 .参数:level:选项类别; option : 具体选项 ; value : 选项值

s.getsockopt(level,option)

返回选项值(value) ##一般在创建套接字后立即设置套接字选项

7. UDP应用之广播

广播 : 一点发送,多点接受
广播地址 : 192.168.207.255
广播风暴 : 一个网络中有大量的广播就会产生广播风暴占用大量带宽
			影响正常的访问速度

接收端:

#broadcast_recv.py
from socket import *


#创建数据报套接字
s = socket(AF_INET,SOCK_DGRAM)

#设置套接字可以发送接受广播
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)

#固定接受端口
s.bind(("0.0.0.0",10241))

while True :
    try:
        msg,addr = s.recvfrom(1024)
        print("从{}获取信息:{}"
              .format(addr,msg.decode()))
        #str.format()
    except (KeyboardInterrupt,SyntaxError) :
        raise
    except Exception as e :
        print(e)

s.close()

发送端:

#broadcast_send.py
from socket import *
from time import sleep

#设置目标地址 ipconfig
dest = ("192.168.0.255",10241)

s = socket(AF_INET,SOCK_DGRAM)

#设置能够发送广播
s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)

while True:
    sleep(2)
    s.sendto("逺離颠倒夢想".encode(),dest)

s.close()

8. TCP应用之HTTP服务

HTTP协议:
	超文本传输协议,是一个应用层协议
主要用途 :
	网页数据的传输 / 也可作为一种数据传输方法!
HTTP协议的特点 :
	1.应用程序协议,传输层使用TCP服务
	2.简单灵活多种语言都有HTTP相关操作接口
	3.无状态的协议,即不记录用户传输的信息(安全性)	
	4.http 1.1 支持持久连接
HTTP请求响应:
	一端通过http请求的格式发送具体请求内容,另一端接受http请求
		按照协议格式解析,获取真实请求后按照http协议响应格式组织回复内容
			回发给请求方,完成一次数据交互
-----------------------------------------------
http 请求(request)
	请求格式 :
		请求行 : 具体的请求类别和请求内容
			格式: 	 GET         /          HTTP/1.1 
					请求类别	   请求内容	    协议版本
					请求类别:表示请求的种类:
						*GET(获取网络资源) *POST(提交一定的附加信息,得到返回结果) 
						HEAD(获取响应头) PUT(更新服务器资源) DELETE(删除服务器资源) 
						CONNECT(-) TRACE(用于测试) OPTIONS(用于获取服务器性能信息)
					请求内容 : /  (获取主页)
		请求头 :对请求内容的具体描述信息
		空行
		请求体 :请求参数或者是提交内容
-----------------------------------------------
http 响应
	响应格式 :
		响应行 : 反馈响应的情况
			格式 : HTTP/1.1		200			OK
					协议版本		响应码	响应的附加信息
					响应码 : 反应响应的具体情况
							1xx(提示信息,表示请求成功)	2xx(响应成功 200等)
							3xx(相应需要重定向) 4xx(客户端错误 404等)
							5xx(服务端错误)
					常见响应码 : 200(响应成功)	404(请求内容不存在)	
					401(没有访问权限) 500(服务器发生未知错误) 503(暂时无法执行)
		响应头 :	对响应内容的具体描述
		空行
		响应体 :返回给请求端的具体内容
要求 :
	1.知道什么是HTTP协议
	2.请求的格式和每一部分的功能
	3.响应的格式和每一部分的功能
	4.常见的请求类型和响应码代表什么
#http_test.py
from socket import *


#创建TCP流式套接字
s = socket(AF_INET,SOCK_STREAM)

#绑定地址
s.bind(('0.0.0.0',8000))

#设置监听
s.listen(5)

while True:
#等待接受连接
    print("waiting for connect...")
    c,addr = s.accept()
    print("connect from",addr)
    #收发消息
    data = c.recv(4096) 
    print("********************")
    print(data)     #浏览器发来的HTTP请求
    print("********************")
#返回消息
    data = '''HTTP/1.1 200 OK
    Content-Encoding:gzip
    Content-Type:text/html

    <h1>Welcome to China</h1>
    '''
    c.send(data.encode())
    c.close()   
    #关闭套接字   
s.close()
#browser address: http://127.0.0.1:8000/

练习:

通过TCP套接字完成一个文件的发送
	将一个文件从客户端发送给服务端
		或者从服务端发送给客户端
文件可以是文本,也可以是图片
#recvfile.py
from socket import *


#创建TCP流式套接字
s = socket()

#绑定地址
s.bind(('127.0.0.1',8888))

#设置监听
s.listen(5)


print("waiting for connect...")
c,addr = s.accept()
print("connect from",addr)
#收发消息
f = open("recv.jpg","wb")
while True:
	data = c.recv(1024)
	if not data:
		break
	#data bytes格式
	f.write(data)
f.close()
c.close()
s.close()
#sendfile.py
from socket import *


#创建TCP流式套接字
s = socket()

s.connect(("127.0.0.1",8888))

f = open('send.jpg','rb')

while True:
    data = f.read(1024)
    if not data :
        break    
    s.send(data)

f.close()
s.close()