网络编程基本语法
1.TCP基本语法
服务端
# 服务端 (七剑下天山)
"""
注意 :
一发一收必须成对,否则会出现数据异常
"""
import socket
# 1.建立一个TCP(socket)对象
sk = socket.socket()
# 2.绑定对应的IP和端口号(注册网络,让其他电脑可以访问到该主机)
sk.bind(("127.0.0.1",8000)) #注意:参数为一个元组
# 3.开启监听(监听是否有设备访问)
sk.listen()
# 4.建立连接 (三次握手)
"""
接收到对象和访问设备的地址:
addr : ('127.0.0.1', 45466)
"""
conn,addr = sk.accept()
# 5.处理收发数据的逻辑
msg = conn.recv(1024) #最多一次接受1024个字节
print(msg.decode("utf-8")) #需要解码成字符串
# 6.断开连接 (四次挥手)
conn.close()
# 7.退还端口
sk.close()
客户端
# 客户端
import socket
# 1.建立一个TCP(socket)对象
sk = socket.socket()
# 2.与服务端建立连接 (需要知道目标主机的IP和端口号)
sk.connect(("127.0.0.1",8000)) #注意: 一个参数元组
# 3.发送数据 (必须是二进制字节流)
strvar = "好人一生平安~"
sk.send(strvar.encode("utf-8"))
# 4.关闭连接
sk.close()
2.TCP循环发消息
服务端
# 循环发消息[服务端]
import socket
sk = socket.socket() #建立TCP对象
sk.bind(("127.0.0.1",8001)) #绑定ip端口注册网络
sk.listen() #开启监听
while True: #服务端永不停机,一直监听
conn,addr = sk.accept() #建立连接(三次招手)
# 循环发消息
while True:
msg = conn.recv(1024) #收消息
print(msg.decode("utf-8"))
# 接收q停止循环
if msg == b"q" or msg == b"Q":
break
strvar = input("请输入内容:")
conn.send(strvar.encode("utf-8")) #发消息
conn.close() #关闭连接 (四次挥手)
sk.close() #退还端口
客户端
# 循环发消息[客户端]
import socket
sk = socket.socket() #建立TCP对象
sk.connect(("127.0.0.1",8001)) #与服务端建立连接
# 循环发消息
while True:
# 发送数据
strvar = input("请输入您要发送的数据(按q结束):")
sk.send(strvar.encode()) #
# 停止循环条件
if strvar.upper() == "Q":
break
# 接收数据
msg = sk.recv(1024)
print(msg.decode())
sk.close() #关闭连接
3.UDP 基本语法
服务端
# 服务端
import socket
# 1.建立一个UDP对象
sk = socket.socket(type = socket.SOCK_DGRAM)
# 2.绑定IP和端口号
sk.bind(("127.0.0.1",8002)) #参数一个元组
# 3.针对udp服务器,第一次只能接受数据
while True:
while True:
msg,addr = sk.recvfrom(1024) #接收访问设备的信息和地址
if msg ==b"q" or msg ==b"Q":
break
print(msg.decode("utf-8"))
strvar = input("请输入发送的内容:")
sk.sendto(strvar.encode("utf-8"),addr) #发送内容
# 4.关闭连接
sk.close()
客户端
# 客户端
import socket
# 1.建立udp对象
sk = socket.socket(type = socket.SOCK_DGRAM)
# 2.收发信息的逻辑
while True:
strvar = input("请输入您要发送的内容(按q退出):")
sk.sendto(strvar.encode("utf-8"),("127.0.0.1",8002)) #发送数据
if strvar.upper() =="Q":
break
msg,addr = sk.recvfrom(1024) #接收数据信息和地址
print(msg.decode("utf-8"))
# 3.关闭连接
sk.close()
4.tcp黏包
原因:
[发送端]出现黏包: 1.数据太小, 2.数据之间时间间隔太短了;
[接收端]出现黏包: 接受数据太慢了
struct 模块
"""
pack 打包
把任意长度数字转换成具有固定4个字节长度的字节流
unpack 解包
把4个字节长度的值恢复成原来的数字,返回的是数字元组
"""
# i => int 要转换的当前类型是整型 数字范围-21亿~21亿
# pack 打包
res = struct.pack("i",191992131) #打包
print(res,len(res)) # b'Cx91qx0b' 4
#unpack 解包成数字元组
tup = struct.unpack("i",res) #解包成数字元组
print(tup,type(tup)) #(191992131,) <class 'tuple'>
res = tup[0] #取出元组数字
print(res,type(res)) # 191992131 <class 'int'>
解决黏包办法(struct模块)
服务端 :
# 服务端
import socket,struct
sk = socket.socket() #建立对象
sk.bind(("127.0.0.1",8000)) #绑定IP端口 注册网络
sk.listen() #打开监听
conn,addr = sk.accept() #建立连接
# 发送消息
strvar = input("请输入你想要发送的数据:")
msg = strvar.encode() #转化字节流
num = len(msg) #字节流大小
res = struct.pack("i",num) #打包4个字节的字节流
conn.send(res) #先发送数据大小
conn.send(msg) #再发送真实数据
conn.send("贾英贺".encode("utf-8"))
conn.close() #关闭连接
sk.close() #退还端口
客户端 :
# 客户端
import socket,struct
sk = socket.socket() #建立对象
sk.connect(("127.0.0.1",8000)) #连接服务端
# 接收消息
msg = sk.recv(4) #第一次接收数据大小
tup = struct.unpack("i",msg) #解包成数字元组
num = tup[0] #提取数字
msg1 = sk.recv(num) #第二次接收真实数据,按第一次提取数字大小截取
print(msg1.decode("utf-8"))
msg2 = sk.recv(1024)
print(msg2.decode("utf-8"))
sk.close()