python学习笔记19

python学习笔记19

TCP协议

在前面实现简单的C\S架构的代码基础上进行简单修改,实现更多功能。

# Server服务端
import socket
sk = socket.socket()
# 设置服务器ip地址以及端口
sk.bind(('127.0.0.1',9011)) # 申请操作系统的资源
# 开始监听访问
sk.listen()

while True: # 用循环控制与多个客户端通信
    # 存储连接和地址
    conn,addr = sk.accept() # TCP协议:握手建立连接
    while True: # 进行多次数据通信
        # 向连接对象发送信息,只能发送字节流
        send_msg = input('>>>')
        conn.send(send_msg.encode('utf-8')) # 将输入内容用utf-8编码
        if send_msg.upper() == 'Q': # 主动结束会话
            break
        # 接收对方的信息,限定最大信息接收值,并用utf-8解码
        msg = conn.recv(1024).decode('utf-8)
        if msg.upper() == 'Q': # 对方结束会话
        	break
        print(msg) 
    # 会话结束,断开连接
    conn.close() # TCP协议:挥手断开连接

# 结束整个服务
sk.close() # 归还操作系统的资源
# Client客户端
import socket
sk = socket.socket()
# 建立连接
sk.connect(('127.0.0.1',9011))
while True: # 进行多次数据通信
    # 接收并打印信息
    msg = sk.recv(1024)
    if msg.upper() == 'Q': # 对方结束会话
        	break
    print(msg.decode('utf-8')) 
    # 发送信息
    send_msg = input('>>>')
    sk.send(send_msg.encode('utf-8'))
    if send_msg.upper() == 'Q': # 主动结束会话
            break
# 关闭连接
sk.close()

UDP协议

# 服务端
import socket
# 设置传输协议为UDP协议
sk = socket.socket(type=socket.SOCK_DGRAM) # UDP协议
sk.bind(('127.0.0.1',9001)) # 设置ip,绑定端口
while True:
    # UDP协议服务端不能先向客户端发送信息
    msg,addr = sk.recvfrom(1024) # 接受信息和对方的ip地址
    print(msg.decode('utf-8'))
    # 向客户端发送信息
    send_msg = input('>>>')
    sk.sendto(send_msg.encode('utf-8'),addr)
sk.close()
# 客户端
import socket
# 设置传输协议为UDP协议
sk = socket.socket(type=socket.SOCK_DGRAM)
# 向服务端发送信息
server = ('127.0.0.1',9001)
while True:
    send_msg = input('>>>')
    # 客户端主动断开连接
    if msg.upper() == 'Q':
        break
    sk.sendto(send_msg.encode('utf-8'),server)
    # 接收服务端发送过来的信息
    msg = sk.recv(1024)
    # 服务端主动断开连接
    if msg.upper() == 'Q':
        break
    print(msg.decode('utf-8'))

粘包现象

粘包现象发生在TCP协议中,因为TCP协议发送的数据间没有边界,并且存在很多优化算法。由于操作系统的缓存,如果发送端两条消息很短并且其发送的时间间隔很短,则可能导致两条消息粘到一起形成粘包现象;另外,如果接收端接收消息不及时也可能形成粘包现象。

解决方法:明确数据边界。可以通过自定义协议,在发送数据时先发送数据的长度,并且这里自定义协议规定表明数据长度的数据所占据的字节长度。

TCP协议完成文件传输

# Server端
import json
import struct
import socket
# 接收
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()

conn,addr = sk.accept()
# 接收文件名和文件大小
# 解决可能粘包的问题
msg_len = conn.recv(4) 
msg_len = struct.unpack('i',msg_len)[0]
msg = conn.recv(msg_len).decode('utf-8')
msg = json.loads(msg)
print(msg)
# 接收文件内容
with open(msg['filename'],'wb') as f:
    while msg['filesize']>0:
        content = sk.recv(1024) 
        # TCP协议在遇到大文件会拆分文件,如果-1024的话可能实际收不到1024字节的文件(因为TCP可能会将字节流分拆为多块)
        msg['filesize'] -= len(content)
        f.write(content)

conn.close()
sk.close()
# Client端
import os
import json
import struct
import socket
# 发送
sk = socket.socket()
sk.connect(('127.0.0.1',9001))

# 发送文件名、文件大小
abs_path = r'C:\Users\16271\Desktop\practice\test.txt' # 文件的绝对路径
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
dic = {'filename':filename,'filesize':filesize}
str_dic = json.dumps(dic)
# 解决可能粘包的问题
b_dic = str_dic.encode('utf-8')
mlen = strut.pack('i',len(b_dic))
sk.send(mlen) # 4个字节表示接下来发送数据的字节长度
sk.send(b_dic)

# 发送文件内容
with open(abs_path,mode='rb') as f:
    while filesize>0:
        content = f.read(1024)
        filesize -= 1024
        sk.send(content)

sk.close()

猜你喜欢

转载自www.cnblogs.com/20-03-14/p/12650178.html