关于P2P通信原理与实现大家可以参见参见P2P通信原理与实现(C语言)文档,我这里就不在详述了。
我们先定义一下信息的结构体,用于发送和接受信息:
/// <summary>信息结构的指针型</summary>
typedef struct _message *lp_message;
/// <summary>信息结构</summary>
typedef struct _message
{
union {
struct { char buff[1030]; };
struct { char cmd[6]; char rt_code[32]; char data[992]; };
};
SOCKADDR_IN addr;
};
在这个结构体中,我采用了一个union同时定义了两种读取数据和写入数据的格式,一种是整个数据buffer的,另一种是将buffer分为cmd、rt_code和data三部分的。其中cmd为固定6个大写字母的通讯命令,rt_code为32字节的运行码,data是命令执行的数据内容。
由于在通讯过程中,这个信息结构体会经常被用到,因此需要定义一个初始化结构指针的函数。
/// <summary>建立一个服务信息</summary>
lp_message newMessage()
{
lp_message msg = (lp_message)malloc(sizeof(_message));
memset(msg->buff, 0, sizeof(_message));
return msg;
}
关于Socket的连接与侦听,p2pserver函数是UDP通讯的核心函数,在这个函数开始我们首先建立UDP的通讯,打开端口,绑定服务,最后启动侦听循环,不断地接收客户端发送过来的信息,一旦收到有效信息,就将信息交由receivedMessage函数来进行处理。
/// <summary>p2p服务</summary>
void p2pserver(u_short port, char* connstr)
{
WSADATA msaData;
if (WSAStartup(MAKEWORD(2, 2), &msaData) != 0)
ErrorHandle("WSAStartup error!");
hServer = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN addrServ;
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(port);
bind(hServer, (SOCKADDR*)&addrServ, sizeof(SOCKADDR));
lp_message msg = newMessage();
int addr_len = sizeof(SOCKADDR_IN);
while (true)
{
int len = recvfrom(hServer, &msg->buff[0], buff_size, 0, (SOCKADDR*)&msg->addr, &addr_len);
if (len > 6)
{
HANDLE h = (HANDLE)_beginthreadex(NULL, 0, &receivedMessage, msg, 0, NULL);
msg = newMessage();
}
}
closesocket(hServer);
WSACleanup();
}
处理相应函数为receivedMessage,这个函数我们将在后面根据业务进行不断的扩展来使用。
/// <summary>处理接收到的信息</summary>
unsigned WINAPI receivedMessage(void *arg)
{
lp_message msg = (lp_message)arg;
printf("Received a [%s] from client %s, string is: %s\n", msg->cmd, inet_ntoa(msg->from->sin_addr), msg->buf);
//do anything
free(msg);
return 0;
}
最后看看主函数的简单写法,如果想以windows服务的方式进行,可以参照windows服务的方式进行改造。
int main()
{
HANDLE hMutex = CreateMutex(NULL, false, (LPCWSTR)"James");
p2pserver(9000, "");
CloseHandle(hMutex);
return 0;
}