服务端:
1 #服务器端 2 import socket 3 4 server = socket.socket() # 声明socket类型,同时生成socket连接对象 5 server.bind(('localhost',9999)) # 绑定地址端口,#特别注意,这里面是一个元组,第一次写可能会漏掉一个括号导致报错 6 server.listen() # 监听 7 8 conn,addr = server.accept() # conn是客户端连接过来在服务器端为其生成的一个连接实例(阻塞) 9 data = conn.recv(1024) # 接收数据,最大1024(阻塞) 10 print("recv:",data) 11 conn.send(data.upper()) # 将接收的数据变成大写,发送回去 12 13 server.close() # 关闭连接
客户端:
1 #客户端 2 import socket 3 4 client = socket.socket() # 声明socket类型,同时生成socket连接对象 5 client.connect(('localhost',9999)) # 特别注意,这里面是一个元组,第一次写可能会漏掉一个括号导致报错 6 7 client.send(b"hello world") # 发送数据 8 data = client.recv(1024) # 接收数据,最大1024(阻塞) 9 print("recv:",data) 10 11 client.close() # 关闭连接
Part.2 socket数据多次发送
服务端:
1 #实现一个连接的连续往返通话 2 import socket 3 4 server = socket.socket() 5 server.bind(('localhost',9999)) 6 server.listen() 7 print("等待消息......") 8 9 conn,addr = server.accept() #等待新的客户端过来 10 while True: # 循环是实现同一个连接内,可以发送多次消息,而不是发送一次就退出了 11 data = conn.recv(1024) 12 print("recv:",data.decode()) 13 # 在windows上面断开客户端,服务端也会终止服务,而在Linux或者mac上断开客户端,这里就接收空数据,并不会断开,一直死循环接收空 14 # 所以下面判断传来的数据是否为空 15 if not data: 16 print(client has lost...) 17 break 18 conn.send(data.upper()) 19 20 server.close()
客户端:
1 import socket 2 3 client = socket.socket() 4 client.connect(('localhost',9999)) 5 6 while True: 7 msg = input(">>:").strip() # strip方法是去掉两头的空格或者指定字符串 8 if len(msg) == 0:continue # 这里不能send空(输入时直接回车),不然客户端就会卡住,所以要加一个判断 9 client.send(msg.encode()) # encode转换为byte,如果是单纯的字符串,前面加b 10 data = client.recv(1024) 11 print('recv:',data.decode()) # decode与encode相反 12 13 client.close()
Part.3 socket服务端执行返回客户端的输入命令
服务端:
1 import socket 2 import os 3 4 server = socket.socket() 5 server.bind(('localhost',9999)) 6 server.listen() 7 8 conn,addr = server.accept() 9 while True: 10 data = conn.recv(1024) 11 print("recv:",data) 12 if not data: 13 print("client had closed......") 14 break 15 res = os.popen(data.decode()).read() # 或者decode("utf-8") 16 # res = os.popen(data).read() 如果执行命令后得到的结果有中文,这样写会报错 17 conn.send(res.encode()) # 或者encode("utf-8") 18 # conn.send(res) 如果执行命令后得到的结果有中文,这样写会报错 19 20 server.close()
客户端:
1 import socket 2 3 client = socket.socket() 4 client.connect(('localhost',9999)) 5 6 while True: 7 cmd = input(">>>:").strip() 8 if len(cmd) == 0:continue 9 client.send(cmd.encode()) 10 res = client.recv(1024) 11 print(res.decode()) 12 13 client.close()
Part.4 客户端断开连接,服务端也能等待下一个连接
服务端:
1 import socket 2 3 server = socket.socket() 4 server.bind(('localhost',9999)) 5 server.listen() 6 7 while True: # 此循环实现,当目前连接的一个客户端断开连接时,服务端能重新等待第二个客户端的连接,而不是关闭客户端就导致服务端也关闭了 8 conn,addr = server.accept() 9 print("建立连接,等待消息。。。") 10 while True: 11 data = conn.recv(1024) 12 if not data:break 13 print("recv:",data.decode()) 14 conn.send(data.upper()) 15 16 server.close()
Part.5 socket处理一次客户请求返回大于1024字节的数据
服务端:
1 import socket 2 import os 3 4 server = socket.socket() 5 server.bind(('localhost',9999)) 6 server.listen() 7 8 while True: 9 conn,addr = server.accept() 10 print("new conn:",addr) 11 while True: 12 data = conn.recv(1024) 13 if not data: 14 print("client has lost...") 15 break 16 print("excution cmd:",data) 17 res = os.popen(data.decode()).read() 18 if len(res) == 0: # res长度为0,说明传过来的命令是错误的,不能返回正确的结果,所以这里做判断 19 res = data.decode() + ": command not found" 20 conn.send(str(len(res.encode())).encode()) # 发送命令结果大小 21 a = conn.recv(1024) # 上下两个send在一块时,会发生粘包,缓冲区将两次发送的数据粘在一块发送,所以这里就设置一个接收消息来分割两次发送 22 # conn.send(str(len(res)).encode()) # 这里的res是命令返回结果,是字符串,这里len针对中文和byte的长度返回值是不同的,所以要转换为byte再len 23 conn.send(res.encode()) 24 25 server.close()
客户端:
1 import socket 2 3 client = socket.socket() 4 client.connect(('localhost',9999)) 5 6 while True: 7 cmd = input(">>>:").strip() 8 if len(cmd) == 0: continue 9 client.send(cmd.encode()) 10 res_size_byte = client.recv(1024) 11 client.send(b'1') # 防止粘包而设置的发送 12 res_size = int(res_size_byte.decode()) # 这是接收到的服务端发来的命令结果总大小 13 recvd_size = 0 #recvd_size是已经接收了的大小值 14 while recvd_size != res_size: #判断目前接收了命令结果的大小是否与服务端发来的结果总大小相同,相同代表接收完了 15 data = client.recv(1024) 16 recvd_size += len(data) # 每次收到的有可能小于1024,所以必须用len判断 17 print(data.decode()) 18 19 client.close()
Part.6 socket实现简单的文件下载功能
服务端:
1 import socket 2 import os 3 # import hashlib 4 5 server = socket.socket() 6 server.bind(('localhost',9999)) 7 server.listen() 8 9 while True: 10 conn,addr = server.accept() 11 print("new conn:",addr) 12 while True: 13 cmd_file = conn.recv(1024) 14 if not cmd_file: continue 15 cmd,filename = cmd_file.decode().split() # 客户端下载文件命令一般是 命令+文件,所以使用split分割出命令和文件 16 if os.path.isfile(filename): # 判断这个是否是文件,可能不存在,也可能是目录 17 f = open(filename,"rb") 18 # m = hashlib.md5() 19 file_size = os.stat(filename).st_size # os.stat是可以获取文件的详细信息,其中st_size表示文件的大小 20 conn.send(str(file_size).encode()) # 将文件大小发送给客户端 21 conn.recv(1024) # 等待客户端确认,防止粘包 22 for line in f: 23 # m.update(line) 24 conn.send(line) 25 f.close() 26 27 server.close()
客户端:
1 import socket 2 3 client = socket.socket() 4 client.connect(('localhost',9999)) 5 6 while True: 7 cmd = input(">>>:").strip() 8 if len(cmd) == 0: continue 9 if cmd.startswith("get"): 10 filename = cmd.split()[1] # 获取文件名 11 client.send(cmd.encode()) 12 file_size_byte = client.recv(1024) # 接收文件大小 13 client.send(b"ready") # 防止粘包 14 file_size = int(file_size_byte.decode()) 15 recvd_size = 0 # 传输接收到了的文件大小 16 f = open(filename,"wb") 17 while recvd_size < file_size: # 传输文件,当传输到最后一次的时候数据大小不一定是1024,所以会发生粘包,因此下面会判断最后一次剩余大小做处理 18 if file_size - recvd_size > 1024: 19 size = 1024 20 else: 21 size = file_size -recvd_size 22 data = client.recv(size) # 如果传输的时候不是最后一次,那么size每次都是1024,如果是最后一次,size就是最后剩余大小 23 recvd_size += len(data) 24 f.write(data) 25 else: 26 print("file transfer finished") 27 f.close() 28 29 client.close()
Part.7 socketserver对socket的再次封装
服务端:
1 import socketserver 2 3 class MyTCPHandler(socketserver.BaseRequestHandler): 4 5 def handle(self): # 服务端跟客户端所有的交互都写在这个handle函数里 6 while True: # 可以多次接收客户端的数据进行处理,而不是进行一次就完了 7 try: 8 self.data = self.request.recv(1024).strip() # 接收数据 9 # if not self.data: break 10 print("{} wrote:".format(self.client_address[0])) 11 print(self.data) 12 self.request.send(self.data.upper()) 13 except ConnectionResetError as e: # 出现这个错误表示客户端已断开,上面的判断数据是否为空 没用 14 print("err:",e) 15 break 16 17 if __name__ == "__main__": 18 HOST,POST = "localhost",9999 19 # server = socketserver.TCPServer((HOST,POST),MyTCPHandler) # 一个服务端处理一个客户端,单线程 20 server = socketserver.ThreadingTCPServer((HOST, POST), MyTCPHandler) # 一个服务端处理多个客户端,多线程 21 server.serve_forever()
eg:实现一个简单的ftp
1.用户登录和注册,用户登录后才能使用
2.每个用户有自己的家目录
3.可以查看当前家目录下的文件
4.用户上传文件到家目录
5.用户从家目录下载文件
6.在上传和下载文件的时候,显示进度条
7.不断开客户端情况下,退出当前用户,可以登录其他用户
#服务端 ftp - main - server.py #代码程序文件 - conf - user #存储用户名和MD5加密密码的文件 -home - dev #dev用户的家目录 - admin - user1 - user2