python内置模块socket模块可解决基于tcp和ucp协议的网络传输
server端:
import socket
sk = socket.socket(type=socket.SOCK_DGRAM) # 声明udp协议
sk.bind(('127.0.0.1', 9090)) # udp和tcp都是绑定自己的ip地址和端口号。udp没有listen和接收对方的地址。谁都可以给我发,只要在线就接。
while True:
msg, addr = sk.recvfrom(1024) # 收信息,最多1024个字节 # 服务端一定要先收到客户端的地址,因为他如果不知道地址也不知道发给谁
print(addr) # ('127.0.0.1', 63045) 发给我信息的ip地址和对方的端口
print(msg.decode('utf-8')) # 从物理层发过来的都是byte类型
msg_send = input('>>>')
sk.sendto(msg_send.encode('utf-8'), addr) # 发信息
sk.close()
client端
import socket
sk = socket.socket(type = socket.SOCK_DGRAM)
while True:
msg_send = input('>>>')
sk.sendto(msg_send.encode('utf-8'),('127.0.0.1',9090))
msg,addr = sk.recvfrom(1024)
print(msg.decode('utf-8'))
print('server addr :',addr) # server addr : ('127.0.0.1', 9090) 服务端的地址
sk.close()
运行结果
>>>吃了吗
吃了
>>>天气怎么样
挺好的
>>>听说明天有台风,做好防范的准备哦
好的
>>>
服务器端:
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 9847)) # 一旦绑定一个地址就是服务器
friends = {'wendy':'\033[1;32;40mwendy : %s\033[0m', 'laura':'\033[1;33;44mlaura : %s\033[0m'} # 设置颜色等
while True:
msg, addr = sk.recvfrom(1024) # 从addr收的信息msg
user, msg = msg.decode('utf-8').split(':')
if msg.strip() == 'q':
continue
else:
print(friends[user]%msg)
send_msg = input('s>>>')
sk.sendto(send_msg.encode('utf-8'), (addr))
sk.close()
客户端1
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ('127.0.0.1', 9847)
user = 'laura'
while True:
send_msg = input('l>>>')
sk.sendto((('%s:%s' % (user, send_msg)).encode('utf-8')), addr)
if send_msg == 'q':
break
msg, _ = sk.recvfrom(1024) # 这里的变量用下划线接收代表此变量是没有用的
print(msg.decode('utf-8'))
sk.close()
客户端2
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ('127.0.0.1', 9847)
user = 'wendy'
while True:
send_msg = input('w>>>')
sk.sendto((('%s:%s' % (user, send_msg)).encode('utf-8')), addr)
if send_msg == 'q':
break
msg, _ = sk.recvfrom(1024)
print(msg.decode('utf-8'))
sk.close
服务器端
import time
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 8848))
while True: # 服务器24小时服务
msg, addr = sk.recvfrom(1024)
fmt_time = time.strftime(msg.decode('utf-8'))
sk.sendto(fmt_time.encode('utf-8'), addr)
sk.close()
客户端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.sendto('%Y-%m-%d %H:%M:%S'.encode('utf-8'), ('127.0.0.1', 8848))
msg, _ = sk.recvfrom(1024)
print(msg.decode('utf-8')) # 运行结果:2018-09-14 21:28:09
sk.close()
步骤
1 在服务器端创建一个对象。相当于总服务台,总机。可以接收很多客户端的请求,sk = socket.socket()
2 绑定本地回环地址,端口,以便别人找到我,因为很多端口已占用。给新手机装卡。sk.bind(‘127.0.0.1’, 9000) # 借用了操作系统的一个端口
3 开机 sk.listen() # 执行完这句后顺利地开启了一个服务端,以ip和端口为标识的服务端,别人连接我的时候触发的是我的accept方法,
4 等电话,如果有人来电话,会显示conn,(给我打电话接收的链接)addr(对方的地址)。sk.accept() # 这个方法会
阻塞,和input方法一样会一直等到别人来连我时,
否则没人连我时不会往下走。拿到conn的链接和addr的地址。而大部分时间都是用conn,于是所有的通话都基于conn来说了,
如conn.send(bytes类型),给对面发信息 conn.recv(数字)收信息,最大能接受1024个字节的数据。如果对面超过1024个字节我只收1024个字节
msg= conn.recv(数字)然后打印等等操作。conn.close()表示和之前的客户端连接已经断开了,sk.close()表示服务已经关掉了。正常情况下一个server端
是不应该轻易关掉的,
5 拿到了conn就可以说话了,拿着链接send消息,conn.send(b’hello’) # 在网络上只能传字节,不能传字符串。
5 开机后用完后要关机。close时返回给系统了。
1 要想给别人打电话,要买个手机 sk = socket.socket()
2 要想给别人打电话自己不需要有卡,输入别人的链接然后连他。sk.connect((‘127.0.0.1’, 9000)) # 服务端的ip地址,服务端的端口
3 用sk接收消息,打印该消息。msg = sk.recv(1024)
import os
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8461))
sk.listen()
conn, addr = sk.accept() # 前面套路都是一样,建服务器,等待有人连我
file_path = r'C:\Users\TR\Desktop\python.mp4' # 要传的文件路径
filename = os.path.basename(file_path) # 获取路径的最后名字,以便对方好存储
conn.send(filename.encode('utf-*')) # 传文件名
file_size = os.path.getsize(file_path) # 获取文件大小
with open(file_path, 'rb') as f: # 视频文件用bytes模式打开
while file_size: # 定义自变量file_size
content = f.read(1024) # 一次读1024个字节,下一次循环时光标自动跳到上次已经读完的末尾
file_size -= len(content) # 每次循环自变量减读取的大小
conn.send(content) # 每次读多少发送多少,知道file_size为0
conn.close() # 循环结束关闭与这个ip地址的链接
sk.close()
client端
import os
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8461)) # 固定格式,连接服务器
filename = sk.recv(1024) # 接收发过来的文件名
filename = filename.decode('utf-8') # 解码文件名
with open(filename, 'wb') as f: # 写模式打开会新建一个文件或覆盖已有同名文件
while True:
content = sk.recv(1024) # 不断接收服务器发过来的信息
if content: # 如果接收的字节不为空
f.write(content) # 就写入文件
else:
break
sk.close()
合包现象
数据很短
时间间隔短
拆包现象
大数据会发生拆分
不会一次性全部发生到对方
对方在接受的时候很可能没有办法一次性接收到所有信息
那么没有接受完的信息很可能和后面的信息粘在一起
粘包现象只发生在tcp协议
tcp协议的传输是流式传输
每一条信息与信息之间是没有边界的
udp协议中是不会发生粘包现象的
适合短数据的发送
不建议发送过长的数据
会增大你数据丢失的几率(因为他抛出去没有回应,也不管有没有那个地址)
在程序中会出现粘包:
收发数据的边界不清晰(分清界限)
接收数据这一段不知道要接收数据的长度到底是多少(告诉接收方这段内容长度是多少)
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9090))
sk.listen()
conn, addr = sk.accept()
conn.send(b'hello')
conn.send(b'world')
conn.close()
sk.close
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 9090))
ret = sk.recv(1024)
print(len(ret), ret) # 2 b'he'
# ret1 = sk.recv(5)
# print(ret1) # b'llowo' tcp属于流传输,没有分隔的界限
sk.close()
import struct
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9090))
sk.listen()
conn, addr = sk.accept()
while True:
s = input('>>>').encode('utf-8') # 参数中默认编码方式为utf-8,返回一个byte格式的obj,encode和decode就是bytes和unicode的相互转化,python中字符串是unicode,转化为utf-8格式的bytes类型
pack_num = struct.pack('i', len(s)) # 之所以用struct,就是为了数字保证转化后只占4个字节,然后发送方发送这个bytes数据,接收方接收的前4个字节就是要传输的文件大小,
conn.send(pack_num)
conn.send(s)
conn.close()
sk.close()
client 端
import socket
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 9090))
while True:
pack_num = sk.recv(4)
num = struct.unpack('i', pack_num)[0]
ret = sk.recv(num)
print(ret.decode('utf-8'))
sk.close()