Networking 如何通过网络在专用应用程序之间进行专用通信?

Networking 如何通过网络在专用应用程序之间进行专用通信?,networking,communication,private,security,Networking,Communication,Private,Security,它基本上是一个安装在多台PC上的应用程序,每个应用程序都维护自己的数据库,当其他应用程序同时启动(连接到同一网络)时,该数据库与其他应用程序同步 我已经使用简单的套接字连接和自定义缓冲区对此进行了测试,但我希望应用程序之间的通信符合公认的标准,并且安全/可靠,而不是试图重新发明轮子 此应用程序对应用程序通信的正常/标准方式是什么?我在哪里可以找到更多信息 此外,在网络上发布和查找其他应用程序时,可以使用哪些技术 编辑: (完善我的问题) 下面gimel指出的pub/sub模型似乎符合我的需要。

它基本上是一个安装在多台PC上的应用程序,每个应用程序都维护自己的数据库,当其他应用程序同时启动(连接到同一网络)时,该数据库与其他应用程序同步

我已经使用简单的套接字连接和自定义缓冲区对此进行了测试,但我希望应用程序之间的通信符合公认的标准,并且安全/可靠,而不是试图重新发明轮子

此应用程序对应用程序通信的正常/标准方式是什么?我在哪里可以找到更多信息

此外,在网络上发布和查找其他应用程序时,可以使用哪些技术


编辑: (完善我的问题)

下面gimel指出的pub/sub模型似乎符合我的需要。然而,它涵盖了很多领域&我真的不知道该从中吸取什么和使用什么

看起来,一旦两个或多个应用程序找到对方,我就需要建立P2P连接——我该怎么做

如果有可用的示例/教程,请指出它们。实现类似于我所需要的东西的小型开源项目/模块也可以使用

我选择的平台是Linux,但基于Windows的示例也非常有用


编辑[09-01-06]:

我目前正在考虑以下选项:

  • (TLDP Howto)-这似乎可行,但我需要进一步研究
  • 使用免费的动态DNS服务器,虽然这看起来有点冒险
  • 使用一些免费的电子邮件工具,例如gmail/yahoo/…,并从那里发送/读取邮件以查找其他应用程序的IP(可以工作,但感觉脏)
  • 有人建议使用webservices,但我不知道它们是如何工作的&将不得不对此进行研究
  • 如果有任何例子,我将非常感谢您对这些选项的意见。不幸的是,我没有选择使用中央服务器或网站(除非可以保证它是免费和永久的)

    [编辑2009-02-19]

    (希望我能接受两个或三个答案!我之所以接受这个答案,是因为它提供了思路和可能性,而其他人则提供了固定但适用的解决方案。感谢所有回答的人,所有这些都有帮助。)

    当我找到/实现我的解决方案时,我会更新这个问题,如果解决方案足够,我会为它创建一个sourceforge项目。(在任何情况下,这都是一个大得多的项目中的小问题。)

    请参阅异步消息传递范例

    一个示例实现是:

    ApacheActiveMQ速度快,支持多种跨语言客户端和协议,具有易于使用的企业集成模式和许多高级功能,同时完全支持JMS 1.1和J2EE 1.4


    听起来您需要分布式缓存或脱机数据库功能-根据您的语言(java/c#/…)有各种各样的选项供您选择…

    您希望这是完全对等的,还是您计划使用一个中央服务器来做除目录之外的任何事情


    对于通信安全性,SSL应该是好的。Java以一种非常简单的方式支持这些,如果您正在使用的话。下面是java 6中SSL的示例

    我设计了一个类似于几年前您所描述的应用程序。我设计了一个在每个桌面上运行的“广告服务器”,并将使用UDP向网络上运行的任何其他程序广播其状态。现在,这有它自己的问题集,取决于您计划如何运行此应用程序。。。但是,这里有一个快速和肮脏的工作方式

    我在一个端口上设置了一个“侦听器”,该端口是通过对数据库服务器和应用程序所连接的数据库进行哈希选择的。这将确保我收到广播的任何人都使用与我相同的数据库,并允许应用程序的多个实例在桌面上运行(这是设计要求)

    然后,我设置了各种“BroadcastMessage()”函数来广播某些事件。我甚至允许使用我的API的开发人员使用自定义负载数据创建自定义事件,然后让程序为该事件注册一个监听器,该监听器将在该事件发生时通知注册器,并向其传递随事件而来的数据

    例如,当应用程序启动时,它会播放一条“我在这里”的消息,任何收听的人都可以吃掉该消息、忽略它或回复它。在“我在这里”中,它包含了正在运行的应用程序的IP地址,因此任何客户端都可以通过TCP连接到它,以进行进一步的数据更新,而这些更新必须交付

    我选择UDP,因为它不是所有其他运行实例都能看到这些广播的要求。这比什么都方便。。。如果当您在同一屏幕上时,有人向数据库添加了一条记录,那么新的记录就会“出现”在您的桌面上

    此外,如果管理员在用户运行应用程序时更改了用户的权限,则用户不必退出并重新进入应用程序,更新会立即接收并处理,用户可以做他们需要做的事情


    在只侦听这些类型消息的线程上设置侦听器非常容易。。。如果您需要示例代码,我也可以提供,但它是在C++中,为Windows设计的,但是它使用原始的WSOCK32.LIB,所以它应该很容易地转移到任何UNIX平台。(只需键入def DWORD,因为我经常使用它。)

    Amazon和Microsoft都有托管队列,您可以将它们用作任意数量的连接、协作应用程序之间的集合点。 亚马逊是商业性的,而不是免费的。目前是免费的,但不能保证永远免费。
    它正好解决了你所面临的问题。为连接的客户端提供发布/订阅模型。

    这里我可能遗漏了一些内容,但我看不到您选择的编程语言。 随风
    void update_database(in_stream, out_stream) {
      Get_Index_Of_Other_Machines_Items(in_stream);
      Send_Index_Of_Items_You_Need(out_stream);
      Get_Items_You_Need(in_stream);
    }
    
    // Some defines that you may see in the code, all of which are user defined...
    #define ADVERTISE_SERVER           0x12345678 // Some unique ID for your advertisement server
    #define ACTIVITY_NONE              0x00000000
    #define ACTIVITY_LOGON             0x00000001
    #define ACTIVITY_LOGOFF            0x00000002
    #define ACTIVITY_RUNNING           0x00000004
    #define ACTIVITY_IDLE              0x00000005
    #define ACTIVITY_SPECIFIC          0x00000006
    
    
    enum Advertisements {
       ADVERTISE_SHUTDOWN,
       ADVERTISE_MESSAGE,
       ADVERTISE_DEBUG,
       ADVERTISE_OVERLAPPED,
       ADVERTISE_BROADCAST_IDENTITY,
       ADVERTISE_IDENTITY,
       ADVERTISE_PARAMETER_CHANGE
    };
    
    struct TAdvertiseServerPacket {
       UINT     uiAdvertisePacketType;
       DWORD    dwPacketLength;
       bool     bRequestReply;
       UINT     uiReplyType;
       bool     bOverlappedResult;
       int      iPacketId;
       bool     bBroadcast;
       char     GuidHash[35];
       BYTE     PacketData[1024];
    };
    
    struct TAdvertiseIdentity {
       TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
       char  szUserName[LEN_APPL_USERNAME + 1];
       char  szDatabase[MAX_PATH];
       char  szConfiguration[MAX_PATH];
       char  szVersion[16];
       long  nUserId;
       char  szApplication[MAX_PATH];
       char  szActivity[33];
       UINT  uiStartupIndc;
    };
    
    struct TAdvertiseMessage {
       char              MessageFrom[LEN_APPL_USERNAME + 1];
       char              MessageText[512];
    };
    
    struct TAdvertiseItemUpdate {
       NMHDR             pNMHDR;
       long              nItemId;
       long              nItemTypeId;
       char              szItemName[LEN_ITEM_NAME + 1];
       bool              bState;
    };
    
    struct TAdvertiseItemUpdateEx {
       NMHDR             pNMHDR;
       long              nItemId;
       bool              bState;
       bool              bBroadcast;
       DWORD             dwDataSize;
       void              *lpBuffer;
    };
    
    struct TOverlappedAdvertisement {
       int               iPacketId;
       BYTE              Data[1020];
    };
    
    DWORD WINAPI CAdvertiseServer::Go(void* tptr)
    {
       CAdvertiseServer *pThis = (CAdvertiseServer*)tptr;
    
       /* Used and reused for Overlapped results, */
       DWORD BufferSize       = 0;
       BYTE *OverlappedBuffer = NULL;
       bool bOverlapped       = false;
       int  iOverlappedId     = 0;
       DWORD BufferPosition   = 0;
       DWORD BytesRecieved    = 0;
       TAdvertiseItemUpdateEx *itemex = NULL;
       UINT uiPacketNumber    = 0;
    
       bool Debug = false;
    #ifdef _DEBUG
       Debug = true;
    #endif
       {
          DWORD dwDebug = 0;
          dwDebug = GetParameter(ADVERTISE_SERVER_DEBUG); // GetParameter is part of the main program used to store running config values.
          if(dwDebug > 0)
          {
             Debug = true;
          }
       }
       WSAData wsaData;
       WSAStartup(MAKEWORD(1,1), &wsaData);
       ServerSocket = socket(PF_INET, SOCK_DGRAM, 0);
       if(ServerSocket == INVALID_SOCKET)
       {
          CLogging Log("Client.log");
          ServerSocket = NULL;
          Log.Log("Could not create server advertisement socket: %d", GetLastError());
          return -1;
       }
       sockaddr_in sin;
       ZeroMemory(&sin, sizeof(sin));
       sin.sin_family = AF_INET;
       sin.sin_port = htons(Port);
       sin.sin_addr.s_addr = INADDR_ANY;
       if(bind(ServerSocket, (sockaddr *)&sin, sizeof(sin)) != 0)
       {
          CLogging Log("Client.log");
          Log.Log("Could not bind server advertisement socket on port: %d Error: %d", Port, GetLastError());
          DWORD dwPort = 0;
          dwPort = GetParameter(ADVERTISE_SERVER_PORT); // Again, used to set the port number, if one could not be figured out.
          if(dwPort > 0)
          {
             return -1;
          }
          Port = 36221;
          sin.sin_port = htons(Port);
          if(bind(ServerSocket, (sockaddr *)&sin, sizeof(sin)) != 0)
          {
             CLogging Log("Client.log");
             Log.Log("Could not bind server advertisement socket on port: %d Error: %d Could not start AdvertiseServer after two attempts.  Server failed.", Port, GetLastError());
             return -1;
          }
       }
    
       SECURITY_ATTRIBUTES sa;
       sa.bInheritHandle = TRUE;
       sa.lpSecurityDescriptor = NULL;
       sa.nLength = sizeof(SECURITY_ATTRIBUTES);
       HANDLE mutex = CreateMutex(NULL, FALSE, "Client.Mutex"); // Used to keep and eye on the main program, if it shuts down, or dies, we need to die.
       while (1)
       {
          TAdvertiseServerPacket ap;
          sockaddr_in sin;
          int fromlen = sizeof(sin);
          fd_set fds;
          FD_ZERO(&fds);
          FD_SET(ServerSocket, &fds);
          timeval tv;
          tv.tv_sec = 15;
          tv.tv_usec = 0;
          int err = select(0, &fds, NULL, NULL, &tv);
          if(err == SOCKET_ERROR)
          {
             CLogging Log("Client.log");
             Log.Log("Advertise: Winsock error: %d", WSAGetLastError());
             Beep(800, 100);
             break;
          }
          if(err == 0)
          {
             if(WaitForSingleObject(mutex, 0) != WAIT_OBJECT_0)
             {
                continue; // Main app is still running
             }
             else
             {
                Beep(800, 100); // Main app has died, so exit our listen thread.
                break;
             }
          }
    
          int r = recvfrom(ServerSocket, (char *)&ap, sizeof(ap), 0, (sockaddr *)&sin, &fromlen);
    
          if(r != sizeof(TAdvertiseServerPacket))
          {
             continue;
          }
          switch(ap.uiAdvertisePacketType)
          {
             // This is where you respond to all your various broadcasts, etc.
             case ADVERTISE_BROADCAST_IDENTITY:
             {
                // None of this code is important, however you do it, is up to you.
                CDataAccess db(CDataAccess::DA_NONE);
                TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
                ZeroMemory(ComputerName, sizeof(ComputerName));
                DWORD len = MAX_COMPUTERNAME_LENGTH;
                GetComputerName(ComputerName, &len);
                if(pThis->szActivity) {
                   CAdvertiseServer::AdvertiseIdentity(ComputerName, CDataAccess::GetLoggedInUserName(), CDataAccess::DatabaseConfiguration(), CDataAccess::DatabaseConfiguration(), ACTIVITY_SPECIFIC, pThis->szActivity, false);
                } else {
                   CAdvertiseServer::AdvertiseIdentity(ComputerName, CDataAccess::GetLoggedInUserName(), CDataAccess::DatabaseConfiguration(), CDataAccess::DatabaseConfiguration(), ACTIVITY_RUNNING, NULL, false);
                }
             }
             case ADVERTISE_IDENTITY:
             {
                TAdvertiseIdentity ident;
                memcpy((void*)&ident, (void*)ap.PacketData, ap.dwPacketLength);
                Listener::iterator theIterator;
                theIterator = pThis->m_Listeners.find(ap.uiAdvertisePacketType);
                if(theIterator == pThis->m_Listeners.end())
                {
    
                   //We got an Identity Broadcast, but we're not listening for them.
                   continue;
                }
                {
                   itemex = new TAdvertiseItemUpdateEx;
                   ZeroMemory(itemex, sizeof(TAdvertiseItemUpdateEx));
                   memcpy((void*)&ident, ap.PacketData, ap.dwPacketLength);
                   itemex->pNMHDR.code     = (*theIterator).first;
                   itemex->pNMHDR.hwndFrom = (*theIterator).second;
                   itemex->pNMHDR.idFrom   = ADVERTISE_SERVER;
                   itemex->dwDataSize      = sizeof(TAdvertiseIdentity);
                   itemex->lpBuffer        = (void*)&ident;
                   SendMessage((*theIterator).second, WM_NOTIFY, 0, (LPARAM)itemex);
                   delete itemex;
                }
             }
             case ADVERTISE_SHUTDOWN:
             {
                TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
                ZeroMemory(ComputerName, sizeof(ComputerName));
                DWORD len = MAX_COMPUTERNAME_LENGTH;
                GetComputerName(ComputerName, &len);
                CString guid;
                guid.Format("%s%s", CDataAccess::DatabaseConfiguration(), ComputerName);
                if(stricmp(ap.GuidHash, CDataAccess::HashPassword(guid)) == 0)
                {
                   return 1;
                }
             }
             case ADVERTISE_MESSAGE:
             {
                TAdvertiseMessage msg;
                memcpy((void*)&msg, (void*)ap.PacketData, ap.dwPacketLength);
                CString msgtext;
                msgtext.Format("Message from: %s\r\n\r\n%s", msg.MessageFrom, msg.MessageText);
                ::MessageBox(NULL, msgtext, "Broadcast Message", MB_ICONINFORMATION | MB_SYSTEMMODAL);
                break;
             }
             case ADVERTISE_OVERLAPPED:
             {
                // I left this code in here, as it's a good example of how you can send large amounts of data over a UDP socket, should you need to do it.
                BufferPosition = (1020 * ((ap.uiReplyType - 1) - 1));
                if(BufferPosition > BufferSize) {
                   BufferPosition -= 1020;
                }
                TOverlappedAdvertisement item;
                ZeroMemory(&item, sizeof(TOverlappedAdvertisement));
                memcpy((void*)&item, (void*)ap.PacketData, ap.dwPacketLength);
                if(item.iPacketId == iOverlappedId)
                {
                   DWORD ToCopy = (sizeof(item.Data) > (BufferSize - BytesRecieved) ? BufferSize - BytesRecieved : sizeof(item.Data));
                   memcpy((void*)&OverlappedBuffer[BufferPosition], (void*)item.Data, ToCopy);
                   BytesRecieved += ToCopy;
                   if(BytesRecieved < BufferSize)
                   {
                      continue;
                   }
                }
             }
             default:
             {
                // What do we do if we get an advertisement we don't know about?
                Listener::iterator theIterator;
                if(bOverlapped == false)
                {
                   theIterator = pThis->m_Listeners.find(ap.uiAdvertisePacketType);
                   if(theIterator == pThis->m_Listeners.end())
                   {
                      continue;
                   }
                }
    
                // Or it could be a data packet
                TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
                ZeroMemory(ComputerName, sizeof(ComputerName));
                DWORD len = MAX_COMPUTERNAME_LENGTH;
                GetComputerName(ComputerName, &len);
                CString guid;
                guid.Format("%s%s", CDataAccess::DatabaseConfiguration(), ComputerName);
                bool FromUs = stricmp(ap.GuidHash, CDataAccess::HashPassword(guid)) == 0;
                if(((FromUs && Debug) || !FromUs) || ap.bBroadcast)
                {
                   if(ap.bOverlappedResult)
                   {
                      if(ap.uiReplyType == 1)
                      {
                         itemex = new TAdvertiseItemUpdateEx;
                         ZeroMemory(itemex, sizeof(TAdvertiseItemUpdateEx));
                         memcpy(itemex, ap.PacketData, ap.dwPacketLength);
                         OverlappedBuffer = (BYTE*)malloc(itemex->dwDataSize);
                         BufferSize = itemex->dwDataSize;
                         ZeroMemory(OverlappedBuffer, itemex->dwDataSize);
                         bOverlapped = true;
                         iOverlappedId = ap.iPacketId;
                         uiPacketNumber = ap.uiReplyType;
                      }
                      continue;
                   }
                   if(bOverlapped)
                   {
                      itemex->pNMHDR.code     = (*theIterator).first;
                      itemex->pNMHDR.hwndFrom = (*theIterator).second;
                      itemex->pNMHDR.idFrom   = ADVERTISE_SERVER;
                      itemex->dwDataSize      = BufferSize;
                      itemex->lpBuffer        = (void*)OverlappedBuffer;
                      SendMessage((*theIterator).second, WM_NOTIFY, 0, (LPARAM)itemex);
                      delete itemex;
                      free(OverlappedBuffer);
                      BufferSize       = 0;
                      OverlappedBuffer = NULL;
                      bOverlapped      = false;
                      iOverlappedId    = 0;
                      BufferPosition   = 0;
                      BytesRecieved    = 0;
                      itemex           = NULL;
                      uiPacketNumber   = 0;
                      break;
                   }
                   TAdvertiseItemUpdate *item = new TAdvertiseItemUpdate;
                   ZeroMemory(item, sizeof(TAdvertiseItemUpdate));
                   memcpy(item, ap.PacketData, ap.dwPacketLength);
    
                   item->pNMHDR.code     = (*theIterator).first;
                   item->pNMHDR.hwndFrom = (*theIterator).second;
                   item->pNMHDR.idFrom   = ADVERTISE_SERVER;
                   SendMessage((*theIterator).second, WM_NOTIFY, 0, (LPARAM)item);
                   delete item;
                }
                break;
             }
          }
       }
       try {
          ResetEvent(ServerMutex);
          CloseHandle(pThis->ServerMutex);
          closesocket(ServerSocket);
          return 0;
       }
       catch(...) {
          closesocket(ServerSocket);
          return -2;
       }
    }
    
    // Here's a couple of the helper functions that do the sending...
    bool CAdvertiseServer::SendAdvertisement(TAdvertiseServerPacket packet)
    {
       TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
       ZeroMemory(ComputerName, sizeof(ComputerName));
       DWORD len = MAX_COMPUTERNAME_LENGTH;
       GetComputerName(ComputerName, &len);
       CString guid;
       guid.Format("%s%s", CDataAccess::DatabaseConfiguration(), ComputerName);
    
       strcpy(packet.GuidHash, CDataAccess::HashPassword(guid));
    
       bool bRetval = false;
       SOCKET s = socket(PF_INET, SOCK_DGRAM, 0);
       if(s != INVALID_SOCKET)
       {
          BOOL tru = TRUE;
          setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&tru, sizeof(tru));
          sockaddr_in sin;
          ZeroMemory(&sin, sizeof(sin));
          sin.sin_family = PF_INET;
          sin.sin_port = htons(Port);
          sin.sin_addr.s_addr = INADDR_BROADCAST;
          if(sendto(s, (char *)&packet, sizeof(packet), 0, (sockaddr *)&sin, sizeof(sin)) > 0)
          {
             bRetval = true;
             if(packet.bRequestReply)
             {
               // Here is where your work comes in, in setting up a reply, or making a TCP connection back to the other client.
             }
          }
          closesocket(s);
       }
       return bRetval;
    }
    
    bool CAdvertiseServer::Advertise(UINT uiAdvertisement, long nItemId, bool bState, void *lpBuffer, DWORD dwDataSize, bool bBroadcast)
    {
       TAdvertiseServerPacket packet;
       ZeroMemory(&packet, sizeof(packet));
       TAdvertiseItemUpdateEx   item;
       ZeroMemory(&item, sizeof(item));
    
       UINT packetnum = 1;
       packet.bOverlappedResult = true;
       packet.bRequestReply = false;
       packet.uiAdvertisePacketType = uiAdvertisement;
       packet.dwPacketLength = sizeof(item);
       packet.uiReplyType = packetnum;
       packet.bBroadcast = bBroadcast;
       item.nItemId = nItemId;
       item.bState  = bState;
       item.dwDataSize = dwDataSize;
       memcpy((void*)packet.PacketData, (void*)&item, sizeof(item));
       packet.iPacketId = GetTickCount();
       if(SendAdvertisement(packet))
       {
          BYTE *TempBuf = new BYTE[dwDataSize];
          memcpy(TempBuf, lpBuffer, dwDataSize);
    
          DWORD pos = 0;
          DWORD BytesLeft = dwDataSize;
          while(BytesLeft)
          {
             TOverlappedAdvertisement item;
             packet.uiAdvertisePacketType = ADVERTISE_OVERLAPPED;
             packet.bOverlappedResult = BytesLeft > 1020;
             item.iPacketId = packet.iPacketId;
             memcpy((void*)item.Data, (void*)&TempBuf[pos], (BytesLeft >= 1020 ? 1020 : BytesLeft));
             memcpy((void*)packet.PacketData, (void*)&item, sizeof(item));
             packet.dwPacketLength = sizeof(item);
             packet.uiReplyType++;
             if(SendAdvertisement(packet))
             {
                if(BytesLeft >= 1020)
                {
                   BytesLeft -= 1020;
                   pos += 1020;
                }
                else
                {
                   BytesLeft = 0;
                }
             }
          }
          delete TempBuf;
       }
       return true;
    }
    
    void CAdvertiseServer::Shutdown()
    {
       TAdvertiseServerPacket packet;
       packet.uiAdvertisePacketType = ADVERTISE_SHUTDOWN;
       SendAdvertisement(packet);
    }