本文最后更新于 194 天前,其中的信息可能已经有所发展或是发生改变。
服务端代码
import socket #套接字
# 1. 创建socket对象
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # AF_INET:基于网络通信的套接字家族 # SOCK_STREAM : 流式协议/tcp协议 # SOCK_DGRAM : 数据报协议/udp协议
# 2.绑定地址 服务端绑定的ip是服务端所在计算机的ip地址 ip + 端口
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #重用绑定的端口和ip
sk.bind(('127.0.0.1',5000)) # 127.0.0.1 本地的一个回环地址
# 3.监听链接请求
sk.listen(5) # 5 代表半链接池大小
print('服务端启动成功,在5000端口等待客户连接')
while True: #持续提供服务
# 4.取出连接请求,开始服务
conn, addr = sk.accept() # conn:连接对象 addr:ip和端口
# print('连接对象:',conn)
print('客户端ip+端口:',addr)
# 5.数据传输
while True:
try: # windows 则用try except 处理
data = conn.recv(1024) #接受客户端数据 1024 :一次最大接收的数据量
except:
break
if not data: #mac 和 linux 处理客户端异常断开
break
data = data.decode('utf-8')
print('客户端发来的数据:',data)
conn.send(data.upper().encode('utf-8')) # 给客户端发数据
# 6.结束服务
conn.close()
# sk.close() # 一般不会关闭服务器
客户端代码
import socket
# 1. 创建socket对象
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.建立连接
sk.connect(('127.0.0.1',5000))
# 3.传输数据
while True:
msg = input('请输入要传输给服务端的数据>>>').strip()
sk.send(msg.encode('utf-8'))
if not msg:
continue
if msg == 'q':
break
data = sk.recv(1024)
data = data.decode('utf-8')
print('服务端发来的数据:',data)
# 关闭连接
sk.close() #必须写
数据接发
先运行服务端,再运行客户端并输入数据
tcp并发服务端
import socket #套接字
import socketserver
class RequestHandle(socketserver.BaseRequestHandler):
def handle(self):
self.request #对于tcp协议相当于 self.request 拿到连接对象
self.client_address #客户端的地址 相当于addr
# 5.数据传输
while True:
try: # windows 则用try except 处理
data = self.request.recv(1024) #接受客户端数据 1024 :一次最大接收的数据量
except:
break
if not data: #mac 和 linux 处理客户端异常断开
break
data = data.decode('utf-8')
print('客户端发来的数据:',data)
self.request.send(data.upper().encode('utf-8')) # 给客户端发数据
# 6.结束服务
self.request.close()
# sk.close() # 一般不会关闭服务器
sk = socketserver.ThreadingTCPServer(('127.0.0.1',5000),RequestHandle)
sk.serve_forever()
cmd客户端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',5000))
while True:
cmd = input('请输入终端命令 >>>').strip()
if not cmd:
continue
client.send(cmd.encode('utf-8'))
# #文件格式
# #先拿到头部长度
# header_size = int(client.recv(4).decode('utf-8'))
# header_json = client.recv(header_size).decode('utf-8') # 用while循环
# header = json.loads(header_json) #反序列化
# print(header)
# data_size = header['file_size']
#先拿到总长度
data_size = int(client.recv(8).decode('gbk'))
recv_size = 0
data = b'' # 如果数据很大,则需要用文件方式
while recv_size < data_size:
res = client.recv(1024)
recv_size += len(res)
data += res
print(data.decode('gbk'))
print(len(data))
并发结果
cmd服务端
import socket
import subprocess
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #重用绑定的端口和ip
server.bind(('127.0.0.1',5000))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
cmd = conn.recv(1024)
except:
break
if not cmd:
break
#执行终端命令
obj = subprocess.Popen(cmd.decode('utf-8'),
shell = True,
stdout =subprocess.PIPE,
stderr = subprocess.PIPE)
out_res = obj.stdout.read()
err_res = obj.stderr.read()
data_size = len(out_res) + len(err_res)
header = bytes(str(data_size),'utf-8').zfill(4) # 固定4个字节长度
# #文件格式
# header = {
# 'file_name' : '文件名',
# 'file_size' : '可以用os.path.getsize获取文件大小',
# 'md5' : '通过hash算法算出md5值' #客户端用同样的算法获取md5值,判断是否相同,可校验文件是否被篡改
# }
# header_json = json.dumps(header) #把字典转为json格式
# header_bytes = header_json.encode('utf-8')
# header_h = bytes(str(len(header_bytes)),'utf-8').zfill(4)
# conn.send(header_h)
# conn.send(header_bytes)
# # 打开文件 for一行行发文件数据
print(header)
conn.send(header)
conn.send(out_res)
conn.send(err_res)
conn.close()
命令运行结果
udp 客户端
udp连着发送不会出现粘包问题
import socket
# 1. 创建socket对象
sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 3.传输数据
while True:
msg = input('请输入要传输给服务端的数据>>>').strip()
sk.sendto(msg.encode('utf-8'),('127.0.0.1',5000)) # 除了传输数据,还要指定发给谁
data,addr = sk.recvfrom(1024)
print(data)
# 关闭连接
sk.close() #必须写
udp 服务端
import socket #套接字
# 1. 创建socket对象
sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # AF_INET:基于网络通信的套接字家族 # SOCK_STREAM : 流式协议/tcp协议 # SOCK_DGRAM : 数据报协议/udp协议
# 2.绑定地址 服务端绑定的ip是服务端所在计算机的ip地址 ip + 端口
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #重用绑定的端口和ip
sk.bind(('127.0.0.1',5000)) # 127.0.0.1 本地的一个回环地址
# udp没有连接,不需要建立连接
# 5.数据传输
while True:
data,addr = sk.recvfrom(1024) #接受客户端数据,还有数据来源 1024 :一次最大接收的数据量
print('客户端发来的数据:',data)
sk.sendto(data.upper(),('127.0.0.1',5000))