TCP/UDP
网络的目的:
信息的传递和数据的共享
地址是用来标记一台主机
IP地址:
作用 – 用来标识网络中的一台主机
构成 – 网络号 主机号
网络号 主机号
192.168.113 .116
IPv4 使用4个字节描述 21亿
IPv6 使用8个字节描述
ping:
能ping通网络一定是通的,ping不代表可能通也可能不通
分类
域名 www.baidu.com –域名解析DNS—> ip 111.13.101.208
ifconfig:
查看网卡中的IP
ping
域名或者IP 测试我与主机网络是否畅通
sudo ifconfig ens33 192.168.1.138
端口:
作用 – 用来标识主机中一个应用程序
IP + 端口的组合 确定网络中唯一的程序
端口用来标识主机中的一个用应用程序
端口的范围:0 - 65535
知名端口:
范围:0-1024(不包含1024)
80端口分配给HTTP服务
21端口分配给FTP服务
https 443
ssh 22
动态端口:
范围:1024-65535
socket:
socket 简称: 套接字
原意:插孔/插座的意思
本质:对底层网络协议TCP/IP的封装,并且提供了一套应用程序接口(API)
套接字使用:
socket() 创建
sendto() 发送数据
recvfrom() 接受数据
close() 关闭
bytes 类型和str类型的相互转化:
str —编码—>bytes
str.encode(“utf-8”)
bytes —解码—->str
bytes.decode(“utf-8”)
如果编码和解码的时候采用的编码方案是UTF-8,不用编码解码
对同一段数据而言,编码的时候有参数用 编码方案 和解码方案必须是同一个编码
在windows的调试助手:
ubuntu — str.encode() —>windows调试助手
bytes.decode(“gbk”)<—
UDP服务器:
bind的作用:告诉操作系统,我的应用要使用某个固定端口
UDP客户端:
import socket
def main():
upd_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
upd_socket.bind(("", 10086))
book = input()
upd_socket.sendto(book.encode(),("192.168.113.85",8081))
while True:
data,adder = upd_socket.recvfrom(1024)
if data:
print("%s" % str(adder))
print("%s" % data.decode())
else:
print("服务器已关闭")
break
upd_socket.close()
if __name__ == '__main__':
main()
UDP服务端:
import socket
def main()
upd_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
upd_socket.bind(("", 8080))
while True:
data,adder = upd_socket.recvfrom(1024)
print("%s" % str(adder))
print("%s" % data.decode())
nook = input()
upd_socket.sendto(nook.encode(),("192.168.113.119", 10086))
if __name__ == '__main__':
main()
UDP简单聊天案例:
import socket
def jieshou(udp_socket):
data, remote_address = udp_socket.recvfrom(1024)
print("收到来自%s的数据:%s" % (str(remote_address), data.decode()))
udp_socket.sendto(data, remote_address)
def fasong(udp_socket):
ip = input("IP地址:")
prot = int(input("端口:"))
book = input("输入内容")
udp_socket.sendto(book.encode(),(ip, prot))
def print_menu():
"""菜单"""
print("请选择功能:1.发送信息 2.接受信息 3.退出")
def main():
"""显示界面"""
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(("",6666))
while True:
print_menu()
num = input("请选择额:")
if num == "1":
fasong(udp_socket)
elif num =="2":
jieshou(udp_socket)
elif num == "3":
break
else:
print("输入错误哦")
udp_socket.close()
if __name__ == '__main__':
main()
UDP发送飞秋消息
import socket
def main()
# 发送飞秋消息
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
i =116
while True:
str1 = input("请输入内容:")
str2 = "1:324244:小道士:ubuntu:32:" + str1
ip_num = "192.168.113." + str(i)
udp_socket.sendto((str2).encode("gbk"),(ip_num,2425))
udp_socket.close()
if __name__ == '__main__':
main()
正向工程:– 表象和自己理解去实现
逆向工作:– 接近底层根据源代码写出自己的
TCP:
TCP是面向连接:
需要进行,创建socket连接、数据传送、关闭连接
在数据传输的时候,必须双方先建立连接,才能通信
TCP 数据传输:
具有应答机制,就是双方都必须有响应,方可传输数据
超时重传,如果发送超时,会进行下次重传,这样就避数据丢包现象
检错功能,能进行数据检错,对发送和接受数据进行效验
流量控制,避免出现阻塞现象,发送方太快,接受方太慢,就容易产生阻塞
TCP与UDP的不同点:
面向连接(确认有创建三方交握,连接已创建才作传输。)
有序数据传输
重发丢失的数据包
舍弃重复的数据包
无差错的数据传输
阻塞/流量控制
UDP 在传输数据时不需要连接,直接发送消息即可
TCP客户端:
import socket
def main():
# 创建客户端套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# connect填写远程服务器ip
tcp_socket.connect(("192.168.113.146", 10050))
while True:
data = input("输入:")
tcp_socket.send(data.encode("GBK"))
recv_data = tcp_socket.recv(10)
# tcp需要判断服务器是否关闭
if recv_data:
print("收到数据" + recv_data.decode("GBK"))
else:
print("对方关闭了链接")
break
tcp_socket.close()
if __name__ == '__main__':
main()
TCP服务端:
import socket
def main():
tcp_server =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.bind(("", 10050))
# listen 变成被动套接字,只有被动套接字才能接受客服端消息
# 128参数值 等待缓冲区,相当于容量,越大就接受越多,具体给多少,要看系统
tcp_server.listen(128)
# 返回值 客户socket---客户套接字
# 客户端地址,标识客户端相关信息系
clie_socket,addrs = tcp_server.accept()
while True: # 在进行无无线循环的时候,必须放在客户套接字下面,接收上面
# recv 是接收从客户端发过来的消息
recv_data = clie_socket.recv(1024)
if recv_data:
clie_socket.send(recv_data)
print(recv_data)
# print(tcp_server)
# print(clie_socket, addrs)
# print(clie_socket)
# print(addrs)
else:
clie_socket.close()
print("客户端已关闭")
break
tcp_server.close()
if __name__ == '__main__':
main()
TCP下载文件案例:
在写代码之前,先分析我们要实现那些功能,怎么实现
1、要写个客户端和一个服务端:
2、客户端需要 创建套接字,进行输入 ip,port,文件名
3、将输入的文件名发送给服务器
4、等待服务器返回我们消息
5、若是服务器有我们需要的文件,将结果返回给客户端,客户端写入新建的文件中
6、服务端:需要创建套接字,进行端口绑定
7、将主动套接字变为被动套接字
8、接受每个客户发送过来的消息
9、服务端接受到客户端发送来的文件名,在我当前目录查找是否存在;
10、若是存在该文件,读取该文件,发送给客户端。
文件下载客户端:
import os
import socket
def main():
# 创建客户端socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器 输入IP ,port ,文件名
server_ip = input("ip地址:")
server_port = int(input("端口:"))
file_name = input("文件名:")
# 连接服务器
tcp_socket.connect((server_ip, server_port))
# 下载的文件名
tcp_socket.send(file_name.encode())
# 接受文件,保存在本地
file = open(file_name, "wb")
count = 0
while True:
data = tcp_socket.recv(1024)
if data:
print("收到消息")
file.write(data)
count += len(data)
else:
file.close()
if count == 0:
os.remove(file_name)
# os.remove(file_name)
print("没有下载文件")
else:
print("文件传输完毕")
break
tcp_socket.close()
if __name__ == '__main__':
main()
文件下载服务器:
import socket
def get_add(file_name):
# 读取文件,判断是否存在
print(file_name)
try: # 读取的文件不存在会报错,需要加入判断
file = open(file_name,"rb")
# 将打开的文件全部读取给data
data = file.read()
print(data)
except Exception as err: # 若是报错了不需要,关闭文件,因为没有打开
print("你下载的文件不存在")
# 若是没有报错,执行else
else:
# 关闭打开的文件/
file.close()
# 关闭了,文件需要返回一个结果,进行二次运算
return data
# 服务端程序在Pycham中不能让在二级目录中,不然会读取不到信息
def main():
# 创建服务器套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置套接字选项 地址重用现象 套接字 选项 重用地址 1代表设置 0代表取消
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定服务器端口
tcp_server.bind(("",6664))
# 变被动套接字 ,起到监听的功能
tcp_server.listen(128)
# 需要多次进行接收每个客户信息,需要无限循环
while True:
# 取出每个客户的套接字,进行每个客户端服务
clie_socket, adder_ip = tcp_server.accept()
# 收到的每个客户端消息
file_name = clie_socket.recv(1024)
print(file_name)
# 判断客户端传过来的文件是否存在 通过封装函数,用reuten返回结果给data,
data = get_add(file_name)
# 判断返回的data是否为空,若是不为空,代表读取到信息,进行读取发送给客户端
if data:
# 需要用每个客户的socket进项发送消息,不能使用接收的scoket
clie_socket.send(data)
# 关闭客户socket
clie_socket.close()
if __name__ == '__main__':
main()
三次握手:
tcp_socket.connect() 发起三次握手,若是没有连接上,就会报错
服务器 会有个2个握手队列,一个正在进行握手队列,一个是以完成握手队列
listen(backlog) 表示指定完成握手队列长度(其他系统一般表示两个队列之和)
apccpet 取出一个队列,队列中就会删除一个
四次挥手:
FIN 完成 finish
主动断开的叫主动端: tcp规定 TIME_WAIT状态。防止ACK丢失,需要保持 30s-2分钟端口不能重新绑定