Page 1 sur 1

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

Publié : 02 Mai 2017 19:18
par ZJP
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.

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

Publié : 11 Mai 2017 14:35
par ZJP
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 );
 }
 

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

Publié : 16 Mai 2017 16:09
par ZJP
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).

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

Publié : 22 Mai 2017 20:00
par E3DStef
Super retour/tuto/article !!!

:coeur: ZJP :super:


Hâte de tester cela ASAP ^^

Merci encore ZJP

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

Publié : 23 Mai 2017 15:39
par ZJP
;-)

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