0813Python总结-tcp,udp及黏包,struck模块

一.tcp基本语法

1.server.py

# ### 服务端
import socket
# 1.创建一个socket对象
sk = socket.socket()
# 2.绑定对应的ip和端口号(让其他主机在网络中可以找得到)
"""127.0.0.1 代表本地ip"""
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(("127.0.0.1", 9000))
# 3.开启监听
sk.listen()
# 4.建立三次握手
conn, addr = sk.accept()
# 5.处理收发数据的逻辑
"""recv 接收 send 发送"""
res = conn.recv(1024)  # 最多一次接收 1024 字节
print(res.decode("utf-8"))
# 6.四次握手
conn.close()
# 7.退还端口
sk.close()

1.client.py

# ### 客户端
import socket
# 1.创建一个socket对象
sk = socket.socket()
# 2.与服务器建立连接
sk.connect(("127.0.0.1", 9000))
# 3.发送数据(只能发送二进制的字节流)
sk.send("北京昨天迎来了暴雨,如今有车是不行的,还得有船".encode("utf-8"))
# 4.退还端口
sk.close()

二.tcp循环发消息

1.server.py

# ### 服务端
import socket
# 1.创建socket对象
sk = socket.socket()
# 在bind方法之前加上这句话,可以让一个端口重复使用
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2.绑定ip的端口号(在网络中注册该主机)
sk.bind(("127.0.0.1", 9000))
# 3.开始监听
sk.listen()
"""
print(conn)
print(addr)
conn:<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9002), raddr=('127.0.0.1', 53620)>
addr:('127.0.0.1', 53620)
"""

# 5.处理收发数据的逻辑
"""send(字节流)"""
"""
conn.send("我去北京先买船".encode("utf-8))
"""
while True:
	# 4.三次握手
	conn, addr = sk.accept()
	while True:
		res = conn.recv(1024)
		print(res.decode())
		strvar = input("请输入服务端要给客户端发送的内容")
		conn.send(strvar.encode())
		if strvar.upper() == "Q":
			break
# 6.四次握手
conn.close()
# 7.退还端口
sk.close()

1.client.py

# ### 客户端
import socket
# 1.创建socket对象
sk = socket.socket()
# 2.连接服务器
sk.connect(("127.0.0.1", 9000))
# 3.收发数据
"""
res = sk.recv(1024)  # 一次最多接收1024个字节
print(res.decode())
"""
while True:
	strvar = input("请输入您要发送的内容:")
	sk.send(strvar.encode())
	res = sk.recv(1024)
	if res == b"q" or res == b"Q":
		break
	print(res.decode())

# 4.关闭连接
sk.close()

三.udp基本语法

1.server.py

# ### 服务端
import socket
# 1.创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
# 2.绑定地址端口号
sk.bind(("127.0.0.1", 9000))
# 3.udp服务器,在一开始只能接收数据
msg, cli_addr = sk.recvfrom(1024)

print(msg.decode())
print(cli_addr)

# 服务端给客户端发送数据
msg = "我是你老娘,赶紧给我回家吃饭"
sk.sendto(msg.encode(), cli_addr)

# 4.关闭连接
sk.close()

1.client.py

# ### 客户端
import socket
# 1.创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)

# 2.收发数据的逻辑
# 发送数据
msg = "你好,你是mm还是gg"
# sendto(消息,(ip,端口号))
sk.sendto(msg.encode(), ("127.0.0.1", 9000))

# 接收数据
msg, server_addr = sk.recvfrom(1024)
print(msg.decode())
print(server_addr)

# 3.关闭连接
sk.close()

四.udp循环发消息

1.server.py

# ### 服务端
import socket
# 1.创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
# 2.绑定地址端口号
sk.bind(("127.0.0.1", 9000))
# 3.udp服务端,在一开始只能接收数据
while True:
	# 接收数据
	msg, cli_addr = sk.recvfrom(1024)
	print(msg.decode())
	message = input("服务端给客户端发送的消息是:")

	# 发送数据
	sk.sendto(message.encode(), cli_addr)

# 4.关闭连接
sk.close()

1.client.py

# ### 客户端
import socket
# 1.创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
# 2.收发数据的逻辑
while True:
	# 发送数据
	message = input("客户端给服务端发送的消息是:")
	sk.sendto(message.encode(), ("127.0.0.1", 9000))

	# 接收数据
	msg, addr = sk.recvfrom(1024)
	if msg == b"q" or msg == b"Q":
		break
	print(msg.decode("utf-8"))

# 3.关闭连接
sk.close()

五.黏包

1.server,py

# ### 服务端
import time
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(("127.0.0.1", 9000))
sk.listen()

conn, addr = sk.accept()

# 处理收发数据的逻辑
# 先发送接下来要发送数据的大小
conn.send("5".encode())
# 发完长度之后,再发数据
conn.send("hello".encode())
conn.send(",world".encode())

conn.close()
sk.close()

1.client.py

# ### 客户端
"""
黏包出现的两种情况:
	(1)发送端发送数据太快
	(2)接收端接收数据太慢
"""
import socket
import time
sk = socket.socket()
sk.connect(("127.0.0.1", 9000))

time.sleep(2)
# 处理收发数据的逻辑
# 先接收接下来要发送数据的大小
res = sk.recv(1)
num = int(res.decode())
# 接收num这么多个字节流
res1 = sk.recv(num)
res2 = sk.recv(1024)
print(res1)  # b'hello'
print(res2)  # b',world'

sk.close()

2.server.py

# ### 服务端
import time
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(("127.0.0.1", 9000))
sk.listen()

conn, addr = sk.accept()

# 处理收发数据的逻辑
# 先发送接下来要发送的数据的大小
conn.send("00000100".encode())
# 发完长度之后,再发数据
msg = "hello" * 20
conn.send(msg.encode())
conn.send(",world".encode())

conn.close()
sk.close()

2.client.py

# ### 客户端
"""
黏包出现的两种情况:
	(1)发送端发送数据太快
	(2)接收端接收数据太慢
"""
import socket
import time
sk = socket.socket()
sk.connect(("127.0.0.1", 9000))

time.sleep(2)
# 发送收发数据的逻辑
# 先接收接下来要发送数据的大小
res = sk.recv(8)
num = int(res.decode())
# 接收num这么多个字节数
res1 = sk.recv(num)
res2 = sk.recv(1024)
print(res1)  # b'hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello'
print(res2)  # b',world'

sk.close()
struck模块

pack:
把任意长度数字转化成具有固定4个字节长度的字节流
unpack:
把4个字节值恢复成原来的数字,返回最终的是元组

pack

import struct
# i => int 要转化的当前的数据是整型
res = struct.pack("i", 9999999)
res = struct.pack("i", 1)
res = struct.pack("i", 43999)
# pack 的范围 -2147483648 ~ 2147483647  21亿次左右
res = struct.pack("i", 2100000000)
print(res, len(res))

unpack

# i => 把对应的数据转化成int整型
tup = struct.unpack("i", res)
print(tup)  # (2100000000,)
print(tup[0])
"""
解决黏包场景:
	应用场景在实时通讯时,需要阅读此次发的消息是什么
不需要解决黏包场景
	下载或者上传文件的时候,最后要把包都结合在一起,黏包无所谓
"""

3.server.py

# ### 服务器
import time
import socket
import struct
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(("127.0.0.1", 9000))
sk.listen()

conn, addr = sk.accept()

# 处理收发数据的逻辑
strvar = input("请输入你要发送的数据")
msg = strvar.encode()
length = len(msg)
res = struct.pack("i", length)

# 第一次发送的是字节流
conn.send(res)

# 第二次发送的是真实的数据
conn.send(msg)

# 第三次发送的是真实的数据
conn.send("世界真美好123".encode())

conn.close()
sk.close()

3.client.py

# ### 客户端
"""
黏包出现的两种情况:
	(1)发送端发送数据太快
	(2)接收端接收数据太慢
"""
import socket
import time
import struct
sk = socket.socket()
sk.connect(("127.0.0.1", 9000))

time.sleep(2)
# 处理收发数据的逻辑

# 第一次接收的是子集长度
n = sk.recv(4)
tup = struct.unpack("i", n)
n = tup[0]

# 第二次接收真实的数据
res = sk.recv(n)
print(res.decode())

# 第三次接收真实的数据
res = sk.recv(1024)
print(res.decode())
sk.close()

猜你喜欢

转载自blog.csdn.net/qq_45957580/article/details/107991731