a wrapper to python native socket module.
| 27 | |
| 28 | |
| 29 | class SocketWrapper: |
| 30 | """a wrapper to python native socket module.""" |
| 31 | |
| 32 | def __init__(self, sock, |
| 33 | receive_bytes_encoding='utf-8', |
| 34 | send_bytes_encoding='utf-8'): |
| 35 | |
| 36 | self.receive_bytes_encoding = receive_bytes_encoding |
| 37 | self.send_bytes_encoding = send_bytes_encoding |
| 38 | |
| 39 | self.terminator = bytearray(chr(0), self.receive_bytes_encoding) |
| 40 | self.__s = sock |
| 41 | self.__buf = bytearray(chr(0) * 0x1000, self.receive_bytes_encoding) |
| 42 | self.__bpos = 0 |
| 43 | self.__bsize = 0 |
| 44 | |
| 45 | def clear_buffer(self): |
| 46 | """reset buffer status for next invocation ``recv_until_terminator()`` |
| 47 | or ``recv_single_byte()``.""" |
| 48 | self.__bpos = 0 |
| 49 | self.__bsize = 0 |
| 50 | |
| 51 | def __fill_buffer(self): |
| 52 | """cache next bytes""" |
| 53 | if self.__bpos >= self.__bsize: |
| 54 | self.__bsize = self.__s.recv_into(self.__buf) |
| 55 | self.__bpos = 0 |
| 56 | |
| 57 | # Returns a single byte from the socket. |
| 58 | def recv_single_byte(self): |
| 59 | """recv a single byte from previously fetched buffer.""" |
| 60 | self.__fill_buffer() |
| 61 | result_byte = self.__buf[self.__bpos] |
| 62 | self.__bpos += 1 |
| 63 | return result_byte |
| 64 | |
| 65 | # Reads until terminator byte is found. |
| 66 | def recv_until_terminator(self): |
| 67 | """recv a nul(or specified as terminator_byte)-terminated whole string |
| 68 | from previously fetched buffer.""" |
| 69 | result_bytes = bytearray() |
| 70 | while True: |
| 71 | self.__fill_buffer() |
| 72 | pos = self.__buf.find(self.terminator, self.__bpos, self.__bsize) |
| 73 | if pos >= 0: |
| 74 | result_bytes.extend(self.__buf[self.__bpos:pos]) |
| 75 | self.__bpos = pos + 1 |
| 76 | break |
| 77 | result_bytes.extend(self.__buf[self.__bpos:self.__bsize]) |
| 78 | self.__bpos = self.__bsize |
| 79 | return result_bytes |
| 80 | |
| 81 | def sendall(self, data): |
| 82 | """sendall with specified byte encoding if data is not bytearray, bytes |
| 83 | (maybe str). if data is bytearray or bytes, it will be passed to native sendall API |
| 84 | directly.""" |
| 85 | if isinstance(data, (bytearray, bytes)): |
| 86 | return self.__s.sendall(data) |