private void SendRequest(string address, int port, int deviceIdx, int selfDeviceIdx)
        {
            PeripheralRequestProtocol p = new PeripheralRequestProtocol();

            p.pcmd       = "request";
            p.devidx     = deviceIdx;
            p.selfdevidx = selfDeviceIdx;
            m_udp.Send(JsonUtility.ToJson(p), address, port);
        }
        void OnReceive(string data, string address, int port)
        {
            if (!IsSelfPacket(address, port))   // 自分が送ったパケットは受けない
            {
                TextMesh text = GetComponentInChildren <TextMesh>();
                if (null != text)
                {
                    text.text = data + " from " + address + ":" + port;
                }

                PeripheralProtocol prtcl = JsonUtility.FromJson <PeripheralProtocol>(data);
                int devidx = GetDeviceIdxFromJson(data);
                //Debug.Log(data + " from " + address + ":" + port + " --- devidx: " + devidx);
                PeripheralConnectedDevice device = null;
                {
                    // 接続しているPeripheralConnectedDeviceを取得する
                    device = FindConnectedDevice(address, port, devidx);
                }

                switch (prtcl.pcmd)
                {
                case "search":
                {           // {"pcmd":"search"}
                            // 機器探索のためのトリガ。broadcastアドレスに送信する。
                    SendAvailable(address, port);
                    Debug.Log("[GogyoNetwork]: Received search pcmd from " + address + ":" + port);
                }
                break;

                case "available":
                {           // {"pcmd":"available","devidx":N,"ability":["ability_1","ability_2",...]}
                            //  機器探索への応答をPeripheralDevice単位で行い,同時にPeripheralDeviceのアビリティの通達を行う。
                    PeripheralAvailable p = JsonUtility.FromJson <PeripheralAvailable>(data);
                    if (!data.Contains("\"devidx\""))
                    {           // HololensのJsonUtilityが、メンバーがいないときに0を代入してしまう問題への対策.
                        p.devidx = -1;
                    }

                    if (null == device)
                    {
                        device = new PeripheralConnectedDevice(address, port, this, p.ability);
                        foreach (string a in p.ability)
                        {
                            device.Ability.Add(a);
                        }

                        Debug.Log("[GogyoNetwork]: Received available pcmd from " + address + ":" + port + ", data: " + data);

                        if (TryMatching(device, p.devidx))
                        {
                            // 対応するデバイスみつかった.
                            SendRequest(address, port, p.devidx, GetDeviceIndex(device.Target));
                            m_connectedDevices.Add(device);
                        }
                    }
                    else
                    {
                        // 既に知ってるデバイスは無視する.
                    }
                }
                break;

                case "request":
                {           // {"pcmd":"request","devidx":N,"selfdevidx":M}
                            // 接続要求の発行。発行元は接続を確立。devidxは要求先のデバイスインデックス。selfdevidxは要求元のデバイスインデックス。
                    PeripheralRequestProtocol p = JsonUtility.FromJson <PeripheralRequestProtocol>(data);
                    if (!data.Contains("\"devidx\""))
                    {           // HololensのJsonUtilityが、メンバーがいないときに0を代入してしまう問題への対策.
                        p.devidx = -1;
                    }
                    Debug.Log("[GogyoNetwork]: Received request pcmd from " + address + ":" + port + ", devidx: " + p.devidx + ", selfdevidx: " + p.selfdevidx);

                    if (p.devidx < m_registeredDevices.Count)
                    {
                        PeripheralConnectedDevice d = new PeripheralConnectedDevice(address, port, this);

                        if (ForceMatching(d, p.devidx, p.selfdevidx))
                        {
                            m_connectedDevices.Add(d);
                            if (null != d.Target)
                            {
                                d.Target.OnRequested();
                            }
                        }
                    }
                }
                break;

                case "alive":
                    if (null != device)
                    {       //  {"pcmd":"request","devidx":N}
                            //  生存確認用の通達。
                        Debug.Log("[GogyoNetwork]: Received alive pcmd from " + address + ":" + port + ": " + device.TargetDeviceIndex);
                        device.ReceiveAlive();
                    }
                    break;

                case "bye":
                {           //  {"pcmd":"bye","devidx":N}
                            //  一定時間生存確認が無い場合に通達して以後切断。
                    if (null != device)
                    {
                        Debug.Log("[GogyoNetwork]: Received bye pcmd from " + address + ":" + port + ": " + device.TargetDeviceIndex);
                        ProcessBye(device);
                    }
                }
                break;

                default:
                    // PeripheralDeviceに処理を委譲.
                    if (null != device && null != device.Target)
                    {
                        device.Target.OnReceive(data, address, port);
                    }
                    else
                    {
                        // devidxが書かれていない通信内容は同じデバイスを登録している全員に伝える.
                        List <PeripheralConnectedDevice> devices = FindByAddress(address, port);
                        foreach (PeripheralConnectedDevice d in devices)
                        {
                            if (null != d.Target)
                            {
                                d.Target.OnReceive(data, address, port);
                            }
                        }
                    }
                    break;
                }
            }
        }