Serveur asynchrone TCP Python. Et le client C# Unity !
Deux exemples très courts pour vous mettre sur les rails, qui envoient et reçoivent du binaire « pur » = très peu de bande passante, avec une connexion persistante.
Je vous donne deux envois-réception qui devraient vous permettre de faire tous vos envois binaires :
- C# : le client envoie un octet, qui correspond à un booléen, pour dire s’il est en big ou little endian ;
- C# : le client envoie un message encodé en UTF-8 (oui j’ai trouve la solution qui fonctionne !) ;
- Python : le serveur lit ce booléen ;
- Python : le serveur lit le message et le dit à voix haute (sous Windows) ;
- Python : le serveur envoie un entier non signé, puis deux float ;
- C# : le client lit l’entier non signé puis deux floats.
Avec ça, vous avez de quoi comprendre et faire tous les échanges que vous voulez !
Serveur asynchrone TCP Python
import asyncio
import struct
from asyncio import StreamWriter, StreamReader
import pythoncom
import win32com.client as win32_client
HOST = '192.168.1.31'
PORT = 9696
async def handle(reader: StreamReader, writer: StreamWriter):
is_little_endian = False
buffer = bytearray(100)
addr = writer.get_extra_info('peername')
print(f"Connected with {addr!r}")
is_little_endian, = struct.unpack_from(
'?', await reader.read(struct.calcsize('c'))
)
print(f'{is_little_endian=}')
data = await reader.read(4096)
message = data.decode('utf8')
pythoncom.CoInitialize()
speak = win32_client.Dispatch('SAPI.SpVoice')
speak.Speak(message)
print(f"Received {message!r} from {addr!r}")
print(f"Send: {message!r}")
float1 = 1.1
float2 = 2.2
struct.pack_into(
# =: native order, std. size & alignment
# H: unsigned short
# f: float
"=Hff",
buffer, 0, 1, float1, float2)
writer.write(buffer)
await writer.drain()
print("Close the connection")
writer.close()
async def main():
server = await asyncio.start_server(handle, HOST, PORT)
print(f'Serving on {server.sockets[0].getsockname()}')
async with server:
await server.serve_forever()
asyncio.run(main())
Client C# Unity
using System;
using System.IO;
using System.Net.Sockets;
using UnityEngine;
public class Connexion : MonoBehaviour
{
public string server;
public string message;
public ushort port;
private void Start()
{
// working sample to send text:
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
byte isLittleEndian = BitConverter.IsLittleEndian ? (byte)1 : (byte)0;
TcpClient client = new TcpClient(server, port);
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.WriteByte(isLittleEndian);
stream.Write(data, 0, data.Length);
Debug.Log($"Sent: {message}");
// read sample
BinaryReader reader = new BinaryReader(stream);
uint len = reader.ReadUInt16();
var x = reader.ReadSingle();
var y = reader.ReadSingle();
Debug.Log("len=" + len);
Debug.Log($"x={x}, y={y}");
}
}
Pour la note, ces deux exemples paraissent simples, mais ils m’ont pris un temps fou, et je n’ai eu aucune réponse au bout de 3 semaines sur stackoverflow…