1.1 UDP套接字
应用层的一种编程方法
socket( ) | 创建套接字 |
bind ( ) | 绑定IP端口 |
sendto ( ) | 发送消息 |
recvfrom ( ) | 接受消息 |
close( ) | 关闭套接字 |
decode ( ) | 解码 |
服务端编写
#模块导入 from socket import * #声明服务端IP,端口 ADDR=('0.0.0.0',8888) #创建udp套接字 Sock_DGRAM 表示选择的是UDP套接字 udp_socket=socket(AF_INET,SOCK_DGRAM) #调用bind绑定地址端口 udp_socket.bind(ADDR) #接受消息 1024 一次能接受的最大字节数 msg,addr=udp_socket.recvfrom(1024) #打印消息跟地址 decode( )解码 print('Recv:',addr,msg.decode() ) #关闭套接字 udp_socket.close( )
客户端编写
#导入模块 from socket import * #确定服务器地址 默认本机IP ADDR=('127.0.0.1,'8888) #创建套接字 udp_socket=socket(AF_INET,SOCK_DGRAM) #接受信息 msg=input('>>:') #发送给服务器 udp_socket.sendto(msg.encode().ADDR) #关闭套接字 udp_socket.close()
客户端 循环接受消息
#客户端循环接受消息 while True: #接受消息 1024一次能接受的最大字节,返回是以元祖的形式 msg,addr=udp_socket.recvfrom(1024) #打印消息跟地址 decode()解码 print('Recv:,'addr,msg.decode()) #回应消息 udp_socket.sendto('收到!'.encode( ).addr) #约定断开通信的 if msg==b'bye': break #关闭套接字 udp_socket.close()
服务端 循环发送消息
#服务端 循环发送消息 while True: #接受信息 msg=input('>>:') #发送给服务器 udp_soket.sendto(msg.encode().ADDR) #接受服务器的消息 data,addr=udp_socket.recvfrom(1024) print('来自服务器的消息:,'data.decode()) #终止服务端循环 if msg=='bye': break #关闭套接字 udp_socket.close()
UDP套接字特点:
·可能会出现数据丢失
·传输过程简单,实现容易
·数据以数据包的形式传输
·数据传输效率高
1.2 TCP套接字
·面向连接的传输服务
1)提供了可靠的数据传递,传输过程当中无丢失,无失序,无差错,无重复
2)可靠性保障机制(自动完成)
·在通信之前需要建立数据连接
·确认应答机制
·通信结束后正常断开连接
·三次握手
客户端向服务器发送报文请求连接
服务收到请求回复报文可以连接
客户端收到回复再次发送报文建立连接
·四次挥手
发起方发送报文请求断开
接收方收到请求回复信息收到,并准备断开
接收方准备完成,再次发送表示可以断开
发送方收到确定,发送最终消息完成断开
·tcp套接字细节
1) tcp连接中一端退出,另一端依然阻塞在recv,此时recv会马上返回一个空字符串
2)如果一端已经不存在,任然通过send向其发送数据则会产生Broken Pipe Error
3)一个服务端可以同时连接多个客户端,也能够被重复连接
socket | 创建套接字 |
bind | 绑定地址 |
listen | 设置监听 |
accept | 等待处理连接 |
send/recv | 发送/接受 消息 |
close | 关闭连接 |
TCP服务端编写
#导入模块 from socket import * #创建套接字 默认是TCP 流式套接字 tcp_socket=socket(AF_INET,SOCK_STREAM) #绑定地址 tcp_socket.bind(('0.0.0.0,'8888)) #设置监听 listen最多能设置1024 Linux自动配置 #具备了监听的属性,被客户端连接的属性 tcp_socket.listen(5) #等待处理客户端的连接 #accept阻塞函数 处理客户端连接请求没有连接则阻塞 #connfd 处理该连接的专门套接字 #addr 客户端地址 print('等待客户端连接中...') connfd,addr=tcp_socket.accept() print('连接的客户端是:',addr) #接受处理客户端的信息 data=connfd.recv(1024) print('消息:',data.decode()) #关闭连接 connfd.close() tcp_socket.close()
TCP客户端编写
#导入模块 from socket import * #创建套接字 tcp_socket=socket() #连接服务端 tcp_socket.connect(('127.0.0.1',8888)) #发送消息 msg=input('>>:') tcp_socket.send(msg.encode()) #关闭连接 tcp_socket.close()
TCP服务端编写 循环
#导入模块 from socket import * #创建套接字 默认是TCP 流式套接字 tcp_socket=socket(AF_INET,SOCK_STREAM) #绑定地址 tcp_socket.bind(('0.0.0.0,'8888)) #设置监听 listen最多能设置1024 Linux自动配置 #具备了监听的属性,被客户端连接的属性 tcp_socket.listen(5) #等待接收客户端的连接 print('等待客户端的连接...') while True: connfd,addr=tcp_socket.accept() print('连接的客户端是:'addr) 接受处理客户端的信息 data=connfd.recv(1024) print('消息:',data.decode()) #回复客户端 connfd,send('收到:'.encode()) connfd.close() #关闭连接 tcp_socket.close()
TCP客户端编写 循环
#导入模块 from socket import * #创建套接字 tcp_socket=socket() #连接服务端 tcp_socket.connect(('127.0.0.1',8888)) #循环发送 while True: msg=input('>>:') tcp_socket.send(msg.encode()) #接收服务端的消息 data=tcp_socket.recv(1024) print('服务端:,'data,decode()) #关闭连接 tcp_socket.close()
1.3 文件传输服务端/客户端
exercise_server 文件传输服务端编写
步骤:
1.建立TCP套接字
2.等待客户端内连接
3.接收图片内容
4.保存图片
5.终止连接
#导入模块 from socket import * import time #创建套接字 socket=socket() #绑定IP socket.listen(5) #创建connfd connfd,addr=socket.accept() #接收客户端的数据 data=connfd.recv(1024*1024) file_name='%d-%d-%d.jpg'%time.localtime()[:3] f=open(file_name,'wb') f.write(data) f.close() #关闭连接 connfd.close() socket.close()
exercise_client 文件传输客户端编写
步骤:
1.创建套接字
2.连接服务端
3.读取文件内容
4.发送文件内容
5.关闭连接
#导入模块 from socket import * #创建套接字 socket=socket() #连接服务端 socket.connect(('127.0.0.1,'8888)) #读入文件内容 f=open('2.jpg','rb') data=f.read() #发送内容 socket.send(data) f.close() socket.close()
粘包问题?
1.】产生原因
·为了解决数据传输中的速率不协调问题,操作系统设置了缓冲区
·实际网络工作过程比较复杂,导致消息收发不一致
·tcp以字节流方式进行数据传输,在接受的时候不区分消息边界
2.】带来的问题?
·如果发送的消息每次都是独立的,需要接收端去独立解析消息时回带来消息误解问题
3.】解决方式
·人工设置消息边界
·减缓消息发送速度
1.4 使用场景
·tcp 适合对准确要求高,传输数据大的场景
(1)文件传输:数据下载(电影音乐),上传照片,访问网站
(2)邮件收发
(3)点对点数据传输:登录,远程,红包,一对一聊天
·udp 适合可靠性要求相对不高,传输自由的场景
(1)视频流:直播,视频聊天
(2)广播:网络广播,群发消息
(3)实时性要求高:游戏等