最近看了其他的一些python实现的socket通信的相关样例或demo代码,一直想找一个较为不错的样例作为编写socket通信的一个样板,固定下编写风格,但是苦于找到的相关样例都是非常简易的一个demo,甚至针对于超过buf_size需要多次recv数据然后进行数据拼接都没有做。这样就导致demo在演示传输较大数据或者是传输文件二进制流,或是其他编码流的方面产生无法解析或无法解码的情况出现。或是在聊天场景下发送超过buf_size的信息会出现收取断层的情况。基于以上问题,设计了这么一个实现思路。 实现思路: 将传输的数据进行base64编码后再添加自定义结尾符号,判断超过buf_size的数据是否收取完成。完整思路过程
针对实际开发环境,在此代码的基础上可以再进行设计通信数据加密,来保证通信过程中数据的安全。
采用RSA+AES混合加密手段来保证通信过程中的数据安全措施,请看另一篇文章。使用RSA+AES混合加密手段加密Socket通信过程中的数据
服务端代码:Server 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 from socketserver import BaseRequestHandler, ThreadingTCPServerimport base64BUF_SIZE = 1024 class Handler (BaseRequestHandler ): @classmethod def en_data (cls, data ): """ 构造bytes数据 :param data: str :return: base64-bytes """ return base64.b64encode(data.encode())+b"#" @classmethod def de_data (cls, data ): """ 解析base64-bytes数据 :param data: base64-bytes :return: str """ return base64.b64decode(data).decode() def handle (self ): while True : data = b'' while True : try : recv_data = self.request.recv(BUF_SIZE) if len (recv_data) > 0 : if recv_data[-1 :] == b'#' : data += recv_data[:-1 ] break else : data += recv_data else : break except Exception as e: print ("Socket receiving data error! | " +str (e)) break if len (data) != 0 : recv = self.de_data(data) print ('收到数据:' , recv) self.request.sendall(self.en_data("服务端已收到数据: " +str (recv))) else : print ("Client Close!" ) break def main (host, port ): ADDR = (host, port) server = ThreadingTCPServer(ADDR, Handler) print ('Server Start!' ) server.serve_forever() if __name__ == '__main__' : main("127.0.0.1" , 8089 )
客户端代码:Client 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 from socket import *import base64class SocketClient (object ): """ 客户端 """ def __init__ (self, host, port ): """ 建立连接对象 :param host: 主机地址 :param port: 主机通信端口 """ self.HOST = host self.PORT = port self._BUFSIZ = 1024 self._ADDR = (self.HOST, self.PORT) self._tcpCliSock = socket(AF_INET, SOCK_STREAM) self._tcpCliSock.connect(self._ADDR) def sent_data (self, data=None ): """ 发送数据,短连接 :param data: 要发送的数据 [str] :return: 收到的服务端发来的数据或状态 [str] """ if data: self._tcpCliSock.sendall(self._en_data(data)) recv = self._recv_data() self.close() return recv else : print ("The sent data is empty or not sent!" ) def sent_data_pending_input (self ): """ 发送数据,长连接 """ lastdata = '' while lastdata != "quit" : lastdata = input ("请输入要发送的数据:" ) if len (lastdata) > 0 : self._tcpCliSock.sendall(self._en_data(lastdata)) recv = self._recv_data() print (recv) else : print ("The sent data is empty or not sent!" ) print ("Client端已退出!" ) def close (self ): """ 关闭连接对象 """ self._tcpCliSock.close() def _recv_data (self ): """ 接收服务端数据 :return: 接收服务端数据-ERROR=None """ data = b'' while True : try : self._tcpCliSock.settimeout(10 ) recv_data = self._tcpCliSock.recv(self._BUFSIZ) if len (recv_data) > 0 : if recv_data[-1 :] == b'#' : data += recv_data[:-1 ] break else : data += recv_data else : break except Exception as e: print ("Socket receiving data error! | " +str (e)) return None if len (data) != 0 : return self._de_data(data) else : return "" @classmethod def _en_data (cls, data ): """ 构造bytes数据 :param data: str :return: base64-bytes """ return base64.b64encode(data.encode())+b"#" @classmethod def _de_data (cls, data ): """ 解析base64-bytes数据 :param data: base64-bytesS :return: str """ return base64.b64decode(data).decode() if __name__ == '__main__' : cli_obj = SocketClient('127.0.0.1' , 8089 ) cli_obj.sent_data_pending_input()