#include "proto.h"
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
int _7777_sock; // bind监听端口
ClientsList _7777_clientsList;
void send_to(int sock, const char *destIP, const int destPort, stMessage *sendbuf) {
struct sockaddr_in server_addr{};
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(destIP);
server_addr.sin_port = htons(destPort);
for (int i = 0; i < 10; i++) {
sendto(sock, sendbuf, sizeof(*sendbuf), 0, (const sockaddr *) &server_addr,
sizeof(server_addr));
usleep(50);// UDP不可靠,故而等待一会 等待对方先发送信息
}
}
void *recvThread7777(void *p) {
ST1 *stp = (ST1 *) p;
ST1 st;
st.sock = stp->sock;
st.sock_addr = stp->sock_addr;
delete stp;
stMessage recvbuf{};
while (true) {
memset(&recvbuf, 0, sizeof(stMessage));
/* UDP */
struct sockaddr_in clientAddr{}; /*本地地址*/
uint32_t addr_len = sizeof(clientAddr);
int ret = recvfrom(st.sock, (char *) &recvbuf, sizeof(stMessage), 0,
(struct sockaddr *) &clientAddr, &addr_len);
if (ret == -1) {
printf("recvfrom %s(%d)\n", strerror(errno), errno);
pthread_exit((void *) 1);
} else {
int messageType = recvbuf.iMessageType;
switch (messageType) {
case LOGIN: // 这case是B要作的事情
// A让你B打洞
{
/*S存上经过NAT-A,NAT-B网关映射转换了的A和B的公网IP和端口号*/
/* client's IP,Port*/
printf("来人了:%s:%d \n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
auto *pClient = new stClient();
pClient->client_addr = clientAddr;
strcpy(pClient->userName, recvbuf.userName);
/* 查找有无次用户名,有则更新,无则插入 */
int clientsCount = (int) _7777_clientsList.size(); // 总客户端数量
if (clientsCount == 0) {
_7777_clientsList.push_back(pClient); // 插入
} else {
for (auto UserIterator = _7777_clientsList.begin();
UserIterator != _7777_clientsList.end(); ++UserIterator) {
if (strcmp(((*UserIterator)->userName), pClient->userName) == 0) // 找到了
{
/* 更新 */
(*UserIterator)->client_addr = pClient->client_addr;
break;
} else //没找到
{
_7777_clientsList.push_back(pClient); // 插入
}
}
}
for (auto UserIterator = _7777_clientsList.begin();
UserIterator != _7777_clientsList.end(); ++UserIterator) // 发送每个客户端的公网ip,port
{
printf("%s\n", (*UserIterator)->userName);
}
break;
}
case P2PTRANS: // 6、S sendto A:【P2PTRANS2】+B经过NAT-B转换后的公网IP地址和映射端口
{
const char *clientBusername = recvbuf.szMessage;
/* 查找用户名B */
sockaddr_in clientBAddr{};
for (auto UserIterator = _7777_clientsList.begin();
UserIterator != _7777_clientsList.end(); ++UserIterator) {
if (strcmp(((*UserIterator)->userName), clientBusername) == 0) // 找到了
{
clientBAddr = (*UserIterator)->client_addr;
break;
}
}
stMessage sendbuff;
sendbuff.iMessageType = P2PTRANS2;
strcpy(sendbuff.userName, recvbuf.userName); // B's name
if (clientBAddr.sin_addr.s_addr == 0) {
strcpy(sendbuff.szMessage, "no this ip");
} else {
char clientBIPandPort[IPANDPORTLen] = "";
memset(clientBIPandPort, 0, IPANDPORTLen);
sprintf(clientBIPandPort, "%s:%d", inet_ntoa(clientBAddr.sin_addr),
ntohs(clientBAddr.sin_port));
strcpy(sendbuff.szMessage, clientBIPandPort); // B's IP:port
}
/* client's IP,Port
inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port)); */
/* UDP */
int sock = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (sock == -1) {
printf("socket %s(%d)\n", strerror(errno), errno);
pthread_exit((void *) 1);
}
send_to(sock, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port), &sendbuff);
break;
}
case P2PSOMEONEWANTTOCALLYOU: // 10、S sendto B:【P2PSOMEONEWANTTOCALLYOU】+A的username+A的公网IP端口
{
const char *clientAusername = recvbuf.userName;
/* 查找用户名B */
sockaddr_in clientAAddr{};
for (auto UserIterator = _7777_clientsList.begin();
UserIterator != _7777_clientsList.end(); ++UserIterator) {
if (strcmp(((*UserIterator)->userName), clientAusername) == 0) // 找到了
{
clientAAddr = (*UserIterator)->client_addr;
break;
}
}
char clientAIPandPort[IPANDPORTLen] = "";
memset(clientAIPandPort, 0, IPANDPORTLen);
sprintf(clientAIPandPort, "%s:%d", inet_ntoa(clientAAddr.sin_addr), ntohs(clientAAddr.sin_port));
stMessage sendbuff;
sendbuff.iMessageType = P2PSOMEONEWANTTOCALLYOU;
strcpy(sendbuff.userName, clientAusername); // A's name
strcpy(sendbuff.szMessage, clientAIPandPort); // A's IP:port
sendbuff.iStringLen = strlen(sendbuff.szMessage) + 1; // +1 == /0
/* client's IP,Port
inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port)); */
/* UDP */
int sock = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (sock == -1) {
printf("socket %s(%d)\n", strerror(errno), errno);
pthread_exit((void *) 1);
}
send_to(sock, inet_ntoa(clientAAddr.sin_addr), ntohs(clientAAddr.sin_port), &sendbuff);
break;
}
}
}
}
}
int listen_sock(int port) {
int sock = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (sock == -1) {
printf("socket %s(%d)\n", strerror(errno), errno);
return sock;
}
int opt = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)// 快速关闭端口,加快程序重启速度
{
printf("SO_REUSEADDR %s(%d)\n", strerror(errno), errno);
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) == -1) {
printf("SO_REUSEADDR %s(
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
nat p2p udp穿墙打洞源码.zip (4个子文件)
p2p_server
proto.h 2KB
main.cpp 9KB
p2p_client
proto.h 2KB
main.cpp 8KB
共 4 条
- 1
资源评论
lj_70596
- 粉丝: 101
- 资源: 3935
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功