socket能实现客户端与服务端的通信。
服务端代码
import socket,os,time,hashlib
server = socket.socket() #创建socker实例
server.bind(("localhost",9981))
#server.bind(("192.168.1.41",9985))
server.listen(5) #开始监听,最多同时连接五个客户端
while True:
print("start to listen...")
coon,addr = server.accept() #接收并建立与客户端的连接,程序在此处开始阻塞,只有等到客户端连接进来开始往下执行
print("build new connection: ", addr)
while True:
cmd = coon.recv(1024).decode() #接收到客户端的byte类型
print("received msgs is : ",cmd)
if (len(cmd.split())) == 1: #如果是linux命令
data = os.popen(cmd).read()
if len(data) == 0:data = "来自客户端的cmd命令不存在"
print(data)
length = len(data.encode("utf-8")) # 计算cmd命令结果的bytes长度
coon.send(str(length).encode("utf-8")) #服务端向客户端发送cmd命令返回值的长度,因为客户端一次接收的数据量有限,需要知道长度,从而确定几次接受完
print("nianbao:",coon.recv(1024).decode())
coon.send(data.encode("utf-8")) #服务端向客户端发送cmd命令返回值,2次连着的send会产生粘包现象,即cmd返回值长度和返回值会一起发送给客户端。中间可以加入coon.recv()或者time.sleep(0.5)来避免
if (len(cmd.split())) > 1:
fname = cmd.split()
if fname[0].startswith('get'):
#客户端要下载文件
if os.path.isfile(fname[1]):
total_size = os.stat(fname[1]).st_size #返回文件的总byte长度
coon.send(str(total_size).encode("utf-8"))
coon.recv(1024)
m = hashlib.md5()
with open(fname[1],'rb') as fr:
for line in fr:
coon.send(line)
m.update(line)
print(coon.recv(1024).decode())
coon.send(m.hexdigest().encode("utf-8"))
else:
print("file is not exist")
coon.send(b"file is not exist")
if not cmd: #如果客户端断开,一面服务端进入死循环
print("client has interrupt")
break
server.close()
客户端代码
import socket
import hashlib
client = socket.socket()
client.connect(("localhost",9981)) #客户端建立连接,localhost是回环地址,一般用于测试
#client.connect(("192.168.1.41",9985)) #客户端建立连接
while True:
msg = input("Enter the infomation sent by client: ")
if len(msg) == 0:continue #不能发送为长度为0 的信息
msg = msg.strip()
if len(msg.split()) == 1:
client.send(msg.encode("utf-8")) #客户端发送消息
total_len = int(client.recv(1024).decode()) #接收cmd返回值的总长
client.send(("客户端接收到了cmd返回值的长度 [%s] " % total_len) .encode("utf-8"))
print("received_len: ",total_len)
recv_len = 0
while recv_len != total_len:
data = client.recv(1024)
recv_len += len(data) #接收到cmd的长度和
print("recv_len: ",recv_len)
print(data.decode())
#ftp below
if len(msg.split()) > 1 and msg.startswith("get"):
file_name = msg.split()[1]
client.send(msg.encode("utf-8"))
file_size = client.recv(1024).decode()
if file_size == "file is not exist": print("file is not exist")
else:
client.send(b"begin to recv file")
fw = open(file_name + ".new",'wb')
m = hashlib.md5()
recv_size = 0
print("file_size ",file_size)
while recv_size < int(file_size):
data = client.recv(1024)
recv_size += len(data)
print("recv_size ",recv_size)
fw.write(data)
m.update(data)
fw.close()
client.send(b"client has recvd done")
print("md5 from server: ",client.recv(1024).decode())
print("mdf from client: ",m.hexdigest())
if msg == 'q':
break #断开连接
client.close()
上面的socket实现的功能
1.在客户端输入df/pwd等linxu命令得到返回值(像top这种持续动态有返回值是不能用的)
2.文件从服务端下载,客户端想服务端上传的没有写
用socket一次只能和一个客户端进行交互,其余的客户端要交互需要排队等候,等前面的断开。如果想连接多个客户端那就要用socketserver 如下,主要是服务端的不同
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("err",e)
break
if __name__ == "__main__":
HOST,PORT = "localhost",9999
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
server.serve_forever() #能连接多个客户端
server.handle_request() #只能连接一个客户端,其余的客户端连接的话会被拒绝