Ok。お約束どおり、私のアプリケーションから抜粋したサンプル コードの一部を以下に示します。これはコンパイルして実行することは想定されていません。これは私が行った方法の例です。あなたは完全に異なることをしなければならないかもしれません。さらに、これは Windows 用に作成されたものであり、コードでわかるように、Windows メッセージを使用してサーバー スレッドとメイン アプリケーションの間でデータを送信しますが、それはすべて、使用方法によって異なります。より興味深い部分をいくつか残しておきましたので、参考にしてください。
セキュリティの部分に関しては、まあ、その部分を処理できると思います。これは、よく知られている暗号を使用して、ネットワークを通過する前にデータを暗号化するという単純な問題であるため、それを含める必要はないと思いました。たとえば、私がどのようにパケット ヘッダーを構築したかを見ることができ、通常は別の構造で構成されるペイロードがあります。したがって、その構造を暗号化してデータとして送信し、反対側で復号化して、適切な構造にコピーします。
// 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);
}