[C# - Windows 32/64] IPC : SharedMemory entre applications sous Unity/.NET

Cette section est destinée aux scripts partagés par la communauté. Chaque post est destiné à un script. Suivez bien les recommandations.
Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

[C# - Windows 32/64] IPC : SharedMemory entre applications sous Unity/.NET

Message par ZJP » 02 Mai 2017 19:18

Bonjour,


Généralement, quand on veut échanger des données entre applications exécutées sur un même poste, on utilise un protocole réseau (UDP ou TCP). Cette solution bien que plus simple a mettre en œuvre est la moins performante et la plus lente.

Sous Windows, dans les InterProcess Communications , il existe une API (le File Mapping) qui simplifie le partage d'un espace mémoire entre process différents (ou identique).

Le Code utilisé n'est pas de moi. Vous trouverez sur le site des exemples, la documentation, ainsi que la DLL Managée et les Sources de celle-ci.

Essayé sous Windows 32 et 64 (tests d'Array) sans aucun souci.

Exemples de base. La DLL est a placer dans un dossier "Plugins".

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SharedMemory;

public class memTestserverIPC : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
		Debug.Log("SharedMemory server");
		
		var serverIPC = new SharedArray<byte>("MySharedArray", 100); // création d'un Byte (Par exemple)  Array commun de 100 éléments.
		
		serverIPC[0] = 123; // premier indice
		serverIPC[serverIPC.Length - 1] = 255; // dernier

		Debug.Log("server buffer lenght " + serverIPC.Length);
	}
}

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SharedMemory;

public class memTestClientIPC : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
		Debug.Log("SharedMemory Client");
		
		var clientIPC = new SharedArray<byte>("MySharedArray"); // ouverture ....

		Debug.Log(clientIPC[0]);
		Debug.Log(clientIPC[clientIPC.Length - 1]);

		Debug.Log("client buffer length " + clientIPC.Length);
	}

}
Pour information, c'est le procédé utilisé par le protocole Spout.

L'IPC en "bref"...
Me rappelle le bon vieux temps du DDE sous VB (très formateur VB, car il fallait compenser les "faiblesses" de l'outil avec L'API Win32 et Cie ). :mrgreen:

Un PDF explicatif, avec exemples en C/C++

Un Serveur et un Client en C, pour ceux qui seraient tentés de construire des DLLs natives. Si si... ;-)

Code : Tout sélectionner

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

#define SHMSZ 27

int main()
{
    char c;
    int shmid;
    key_t key;
    char *shm, *s;
    
    /*
     * We'll name our shared memory segment
     * "5678".
     * Be careful about the key. For safety, it is better to use ftok() 
     */
    key = 5678;

    /*
     * Create the segment.
     */
    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    /*
     * Now we attach the segment to our data space.
     */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    /*
     * Now put some things into the memory for the
     * other process to read.
     */
    s = shm;

    for (c = 'a'; c <= 'z'; c++)
        *s++ = c;
    *s = NULL;

    /*
     * Finally, we wait until the other process 
     * changes the first character of our memory
     * to '*', indicating that it has read what 
     * we put there.
     */
    while (*shm != '*')
        sleep(1);

    if (shmdt(shm)==-1)
       perror("shmop: shmdt failed");

    exit(0);
}

Code : Tout sélectionner

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

#define SHMSZ  27

main()
{
    int shmid;
    key_t key;
    char *shm, *s;

    /*
     * We need to get the segment named
     * "5678", created by the server.
     */
    key = 5678;

    /*
     * Locate the segment.
     */
    if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    /*
     * Now we attach the segment to our data space.
     */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    /*
     * Now read what the server put in the memory.
     */
    for (s = shm; *s != NULL; s++)
        putchar(*s);
    putchar('\n');

    /*
     * Finally, change the first character of the 
     * segment to '*', indicating we have read 
     * the segment.
     */
    *shm = '*';

    exit(0);
}




Have Fun.

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [C# - Windows 32/64] IPC : SharedMemory entre applications sous Unity/.NET

Message par ZJP » 11 Mai 2017 14:35

Mise à jour du Serveur de Reconnaissance Vocale avec une version qui utilise le Shared Memory. Voir le source.

La partie qui se charge de "poker" le mot reconnu est quand même plus simple (et plus rapide) qu'un transfert via UDP/TCP. ;-)

"Poke"

Code : Tout sélectionner

// Put the Word in the Shared array +++++++++++++
data = Encoding.ASCII.GetBytes(wordRecognized);
for (int i = 0; i < data.Length; i++)
{   
  serverIPC [i + 2] = data[i];
}
serverIPC[1] = (Byte)data.Length;
serverIPC[0] = 1; // New Word in the Buffer !!!
// Put the Word in the Shared array +++++++++++++

Le "Peek" : Réception coté Unity.

Code : Tout sélectionner

 if (clientIPC[0] == 1) // New Word in the Buffer ???
 {
	// Yes
	string response = string.Empty;
	for (int i = 0; i < clientIPC[1]; i++) {   
	   response += (char)clientIPC[i + 2];
	}
	clientIPC[0] = 0; // I got the Word. Put a new one.
	Debug.Log("New Word is coming !!! : " + response );
 }
 

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [C# - Windows 32/64] IPC : SharedMemory entre applications sous Unity/.NET

Message par ZJP » 16 Mai 2017 16:09

Vraiment intéressant sous Unity le shared.

Exemples d’essais effectués entre deux applications : un échange de position entre un "Player" et un Editeur de placement.
Notez que j'aurais pu utiliser des "Vector3", mais le "float" m'a semblé plus...souple pour la mise en place du "protocole" d'échange.


Serveur (Poke)

Code : Tout sélectionner

// **************************************************************
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SharedMemory;
using System.IO;

public class PokePos : MonoBehaviour {

	SharedArray<float> serverIPC;
	private Vector3 tempoV3 = new Vector3(0.0f, 0.0f, 0.0f);

	void Start () {
		serverIPC = new SharedArray<float>("MoonsPos", 4);
		serverIPC[0] = 0.0f; // Pas de new Pos
		Debug.Log("server buffer lenght " + serverIPC.Length);
	}
	
	// Update is called once per frame
	void FixedUpdate ()	{
		if (serverIPC[0] < 0.5f) {
			tempoV3 = transform.position;
			Debug.Log(tempoV3);
			serverIPC[1] = tempoV3.x;
			serverIPC[2] = tempoV3.y;
			serverIPC[3] = tempoV3.z;
			serverIPC[0] = 1.0f;
		}
	}
}
// **************************************************************



Client (Peek)

Code : Tout sélectionner

// *******************************************************************
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SharedMemory;
using System.IO;

public class PeekPos : MonoBehaviour {
	SharedArray<float> clientIPC;
	private bool sArray;
	private Vector3 tempoV3 = new Vector3(0.0f, 0.0f, 0.0f);

	void Start () {
		Debug.Log("SharedMemory Client");
		sArray = true;
		try   { clientIPC = new SharedArray<float>("MoonsPos"); }
        catch ( FileNotFoundException ex) { sArray = false; }
	}

	void FixedUpdate() {
		if (!sArray) return;
		if (!clientIPC.ShuttingDown) {
			if (clientIPC[0] > 0.5f) {// New Pos in the Buffer
				Debug.Log("New Pos is coming !!!");
				tempoV3.x = clientIPC[1];
				tempoV3.y = clientIPC[2];
				tempoV3.z = clientIPC[3];
				Debug.Log(tempoV3);
				transform.position = tempoV3;
				clientIPC[0] = 0.0f; // I got the Pos. Put a new one.
			}
		}
	}
}
// *******************************************************************


PS :
Une version des sources de la librairie en pièce jointe. La compilation se fait sans souci sous MonoDevelop (fichier . sln).
Pièces jointes
SharedMemory-src-2015.7z
(44.38 Kio) Téléchargé 247 fois

Avatar de l’utilisateur
E3DStef
Administrateur
Administrateur
Messages : 1646
Inscription : 14 Juil 2013 18:30
Localisation : https://www.carte-des-membres.com/fr/Unity3D-France/

Re: [C# - Windows 32/64] IPC : SharedMemory entre applications sous Unity/.NET

Message par E3DStef » 22 Mai 2017 20:00

Super retour/tuto/article !!!

:coeur: ZJP :super:


Hâte de tester cela ASAP ^^

Merci encore ZJP
Le Savoir n'est Précieux que s'il est Partagé

Si besoin urgent de me contacter, faites moi un mail sur : franceunity3d@gmail.com

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [C# - Windows 32/64] IPC : SharedMemory entre applications sous Unity/.NET

Message par ZJP » 23 Mai 2017 15:39

;-)

Le savoir partagé, toussa.... :mrgreen:

Répondre

Revenir vers « Scripts »