or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

custom-objects.mdindex.mdnetwork.mdobjectid.mdserialization.mdtypes.md

network.mddocs/

0

# Network Socket Extensions

1

2

Socket patching capabilities that extend Python socket objects with atomic BSON transmission methods. This enables seamless BSON communication over network connections with automatic serialization and deserialization.

3

4

## Capabilities

5

6

### Socket Patching

7

8

Patches the Python socket class to add BSON object transmission methods, enabling atomic send and receive operations for BSON data.

9

10

```python { .api }

11

def patch_socket():

12

"""

13

Patch the Python socket class with BSON transmission methods.

14

15

Adds the following methods to socket objects:

16

- recvbytes(bytes_needed, sock_buf=None): Read exact number of bytes

17

- recvobj(): Read complete BSON object

18

- sendobj(obj): Send BSON object atomically

19

20

Note: Must be called before creating socket objects to enable BSON methods

21

"""

22

```

23

24

Usage example:

25

26

```python

27

import socket

28

import bson

29

30

# Patch socket class first

31

bson.patch_socket()

32

33

# Create socket with BSON capabilities

34

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

35

36

# Now socket has BSON methods available

37

# sock.sendobj({"message": "hello"})

38

# obj = sock.recvobj()

39

```

40

41

### Atomic Byte Reception

42

43

Receive an exact number of bytes from a socket atomically, handling partial reads and connection closures gracefully.

44

45

```python { .api }

46

def recvbytes(self, bytes_needed, sock_buf=None):

47

"""

48

Atomically read exact number of bytes from socket.

49

50

This method is added to socket objects by patch_socket().

51

52

Parameters:

53

- bytes_needed: int, exact number of bytes to read

54

- sock_buf: BytesIO buffer to append to (optional, creates new if None)

55

56

Returns:

57

BytesIO: Buffer containing exactly bytes_needed bytes, or None if socket closed

58

59

Raises:

60

socket.error: On network errors

61

"""

62

```

63

64

Usage example:

65

66

```python

67

import socket

68

import bson

69

from io import BytesIO

70

71

bson.patch_socket()

72

73

# Server side example

74

server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

75

server_sock.bind(('localhost', 8080))

76

server_sock.listen(1)

77

78

conn, addr = server_sock.accept()

79

80

# Read exactly 100 bytes

81

data_buffer = conn.recvbytes(100)

82

if data_buffer is not None:

83

raw_data = data_buffer.getvalue()

84

print(f"Received {len(raw_data)} bytes")

85

else:

86

print("Connection closed by client")

87

88

# Reuse buffer for multiple reads

89

buffer = BytesIO()

90

header = conn.recvbytes(4, buffer) # Read 4-byte header

91

if header is not None:

92

payload = conn.recvbytes(96, header) # Read 96 more bytes into same buffer

93

if payload is not None:

94

total_data = payload.getvalue() # Now contains 100 bytes total

95

```

96

97

### BSON Object Reception

98

99

Receive complete BSON objects from socket, automatically handling message framing and deserialization.

100

101

```python { .api }

102

def recvobj(self):

103

"""

104

Atomically receive a complete BSON object from socket.

105

106

This method is added to socket objects by patch_socket().

107

Handles BSON message framing automatically by reading length header first.

108

109

Returns:

110

dict: Deserialized BSON object, or None if socket closed

111

112

Raises:

113

socket.error: On network errors

114

ValueError: If BSON data is malformed

115

"""

116

```

117

118

Usage example:

119

120

```python

121

import socket

122

import bson

123

124

bson.patch_socket()

125

126

# Server receiving BSON objects

127

server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

128

server_sock.bind(('localhost', 8080))

129

server_sock.listen(1)

130

131

conn, addr = server_sock.accept()

132

133

while True:

134

# Receive BSON object

135

obj = conn.recvobj()

136

137

if obj is None:

138

print("Client disconnected")

139

break

140

141

print(f"Received: {obj}")

142

143

# Process the received object

144

if obj.get('command') == 'quit':

145

break

146

147

conn.close()

148

```

149

150

### BSON Object Transmission

151

152

Send Python objects as BSON over socket connections with automatic serialization and framing.

153

154

```python { .api }

155

def sendobj(self, obj):

156

"""

157

Atomically send a BSON object over socket.

158

159

This method is added to socket objects by patch_socket().

160

Automatically serializes object to BSON and sends with proper framing.

161

162

Parameters:

163

- obj: dict or BSONCoding object to send

164

165

Raises:

166

socket.error: On network errors

167

UnknownSerializerError: If object cannot be serialized

168

"""

169

```

170

171

Usage example:

172

173

```python

174

import socket

175

import bson

176

177

bson.patch_socket()

178

179

# Client sending BSON objects

180

client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

181

client_sock.connect(('localhost', 8080))

182

183

# Send various BSON objects

184

messages = [

185

{"type": "greeting", "message": "Hello server!"},

186

{"type": "data", "values": [1, 2, 3, 4, 5]},

187

{"type": "user", "name": "Alice", "age": 30},

188

{"command": "quit"}

189

]

190

191

for msg in messages:

192

client_sock.sendobj(msg)

193

print(f"Sent: {msg}")

194

195

client_sock.close()

196

```

197

198

## Complete Client-Server Example

199

200

```python

201

# Server (server.py)

202

import socket

203

import threading

204

import bson

205

206

bson.patch_socket()

207

208

def handle_client(conn, addr):

209

print(f"Connected by {addr}")

210

211

while True:

212

try:

213

# Receive BSON object

214

obj = conn.recvobj()

215

216

if obj is None:

217

print(f"Client {addr} disconnected")

218

break

219

220

print(f"Received from {addr}: {obj}")

221

222

# Echo back with server timestamp

223

import time

224

response = {

225

"echo": obj,

226

"server_time": time.time(),

227

"status": "received"

228

}

229

conn.sendobj(response)

230

231

except Exception as e:

232

print(f"Error handling {addr}: {e}")

233

break

234

235

conn.close()

236

237

# Start server

238

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

239

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

240

server.bind(('localhost', 8080))

241

server.listen(5)

242

print("Server listening on port 8080")

243

244

while True:

245

conn, addr = server.accept()

246

thread = threading.Thread(target=handle_client, args=(conn, addr))

247

thread.start()

248

```

249

250

```python

251

# Client (client.py)

252

import socket

253

import bson

254

import time

255

256

bson.patch_socket()

257

258

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

259

client.connect(('localhost', 8080))

260

261

# Send test messages

262

test_data = [

263

{"message": "Hello", "id": 1},

264

{"data": [10, 20, 30], "type": "array"},

265

{"user": {"name": "Bob", "role": "admin"}, "nested": True}

266

]

267

268

for data in test_data:

269

# Send object

270

client.sendobj(data)

271

272

# Receive response

273

response = client.recvobj()

274

if response:

275

print(f"Server response: {response}")

276

277

time.sleep(1)

278

279

client.close()

280

```

281

282

## Error Handling

283

284

### Network Errors

285

286

All socket methods can raise standard socket exceptions:

287

- `socket.error`: General network errors

288

- `ConnectionResetError`: Connection closed by peer

289

- `ConnectionAbortedError`: Connection aborted

290

- `TimeoutError`: Socket timeout

291

292

### BSON Errors

293

294

BSON-specific errors during network operations:

295

- `UnknownSerializerError`: Cannot serialize object in `sendobj()`

296

- `ValueError`: Malformed BSON data in `recvobj()`

297

298

### Connection Closure Detection

299

300

Methods return `None` when the remote end closes the connection cleanly:

301

302

```python

303

obj = sock.recvobj()

304

if obj is None:

305

# Connection closed cleanly

306

print("Peer disconnected")

307

else:

308

# Process received object

309

handle_message(obj)

310

```

311

312

## Implementation Notes

313

314

- `recvbytes()` reads data in chunks up to 32KB to handle large messages efficiently

315

- `recvobj()` first reads the 4-byte BSON length header, then the remaining message

316

- `sendobj()` uses `socket.sendall()` to ensure complete transmission

317

- All methods handle both Python 2 and 3 byte string differences transparently

318

- Socket patching is global and affects all socket instances created after patching