UDP 打洞
一下记录我的UDP打洞的代码,这个代码在我的服务器上没有成功,有可能是网络类型的原因。
你去网上一搜就能搜到4种网络类型,全锥,受限,端口受限,对称。
然后分别的打洞的理论上的说明。
然后怎么测试你的服务器是什么类型的网络呢?
你会搜索到nattypetester这个软件,但是这个软件怎么用呢?
emmmm,就不好搜了,据我查到的东西猜测,可能需要在服务器搭建什么服务(stun?),这这这,我的服务器就那一个还有用,暂时不折腾了,等啥时候有机会能白嫖一个啥的我在测试吧。
下面是三个代码,服务器:s.cpp 内网客户端A: a.cpp 内网客户端B: b.cpp
代码应该是linuxwindows通用的,所以稍微有点臃肿。
基本思路:
服务器绑定9999端口,等待消息
A向服务器发送hello, 服务器获得到A过来的socket的ip和端口,记录到aAddr中(认为第一个过来的是A)
B向服务器发送hello, 服务器获得到B过来的socket的ip和端口,记录到bAddr中(认为第二个过来的是B)
然后将A的ip和端口发给B,将B的ip和端口发给A
然后A向B发消息,B向A发消息
s.cpp
#include <stdio.h>
#include <iostream>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#define sendto(a, b, c, d, e, f) sendto(a, b, c, d, e, f)
#define recvfrom(a, b, c, d, e, f) recvfrom(a, b, c, d, e, f)
typedef int socklen_t;
#else
#define sendto(a, b, c, d, e, f) sendto(a, b, c, d, e, (socklen_t)f)
#define recvfrom(a, b, c, d, e, f) recvfrom(a, b, c, d, e, (socklen_t *)f)
#endif
#define SPORT 9999
#define BUF_SIZE 100
using namespace std;
sockaddr aAddr, bAddr;
int main(){
#ifdef _WIN32
WSADATA wsaData;
WSAStartup( MAKEWORD(2, 2), &wsaData);
#endif
//创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
//绑定套接字
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr)); //每个字节都用0填充
servAddr.sin_family = PF_INET; //使用IPv4地址
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址
servAddr.sin_port = htons(SPORT); //端口
bind(sock, (sockaddr*)&servAddr, sizeof(sockaddr));
//接收客户端请求
sockaddr clientAddr; //客户端地址信息
int sockaddr_size = sizeof(sockaddr);
char buffer[BUF_SIZE]; //缓冲区
memset(buffer, 0, sizeof(buffer));
int cnt=0;
while(1){
int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &clientAddr, &sockaddr_size);
sockaddr_in *clientAddr_in = (sockaddr_in *)&clientAddr;
printf("%s\n", buffer);
printf("%s:%d\n", inet_ntoa(clientAddr_in->sin_addr), ntohs(clientAddr_in->sin_port));
fflush(stdout);
if(cnt==0)
{
memcpy(&aAddr, &clientAddr, sizeof(clientAddr));
cnt++;
}
else if(cnt==1)
{
if(strcmp(aAddr.sa_data, clientAddr.sa_data)!=0)
{
memcpy(&bAddr, &clientAddr, sizeof(clientAddr));
}
cnt++;
}
if(cnt==2)
{
sockaddr_in *t_addr_in = (sockaddr_in *)&aAddr;
printf("A: %s:%d\n", inet_ntoa(t_addr_in->sin_addr), ntohs(t_addr_in->sin_port));
t_addr_in = (sockaddr_in *)&bAddr;
printf("B: %s:%d\n", inet_ntoa(t_addr_in->sin_addr), ntohs(t_addr_in->sin_port));
fflush(stdout);
char t_buff[BUF_SIZE];
memset(t_buff, 0, sizeof(t_buff));
memcpy(t_buff, (char *)&bAddr, sizeof(bAddr));
sendto(sock, t_buff, sizeof(bAddr), 0, &aAddr, sizeof(aAddr));
memset(t_buff, 0, sizeof(t_buff));
memcpy(t_buff, (char *)&aAddr, sizeof(aAddr));
sendto(sock, t_buff, sizeof(aAddr), 0, &bAddr, sizeof(bAddr));
printf("info swap done!\n");
fflush(stdout);
memset(&aAddr, 0, sizeof(aAddr));
memset(&bAddr, 0, sizeof(bAddr));
cnt=0;
}
}
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
return 0;
}
a.cpp
#include <stdio.h>
#include <iostream>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#define sendto(a, b, c, d, e, f) sendto(a, b, c, d, e, f)
#define recvfrom(a, b, c, d, e, f) recvfrom(a, b, c, d, e, f)
typedef int socklen_t;
#else
#define sendto(a, b, c, d, e, f) sendto(a, b, c, d, e, (socklen_t)f)
#define recvfrom(a, b, c, d, e, f) recvfrom(a, b, c, d, e, (socklen_t *)f)
#endif
#define SPORT 9999
#define BUF_SIZE 100
#define SERVER_IP "127.0.0.1"
using namespace std;
int main(){
#ifdef _WIN32
WSADATA wsaData;
WSAStartup( MAKEWORD(2, 2), &wsaData);
#endif
//创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
//填写服务器地址信息
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr)); //每个字节都用0填充
servAddr.sin_family = PF_INET;
servAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
servAddr.sin_port = htons(SPORT);
sockaddr_in t_addr;
socklen_t t_len;
getsockname(sock, (sockaddr *)&t_addr, &t_len);
printf("%s:%d\n", inet_ntoa(t_addr.sin_addr), ntohs(t_addr.sin_port));
//向服务器发送自己的ip和端口
char buffer[BUF_SIZE]="hello I am A";//缓冲区
sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
getsockname(sock, (sockaddr *)&t_addr, &t_len);
printf("%s:%d\n", inet_ntoa(t_addr.sin_addr), ntohs(t_addr.sin_port));
sockaddr bAddr, sAddr;
int sockaddr_size = sizeof(sockaddr);
memset(buffer, 0, sizeof(buffer));
int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &sAddr, &sockaddr_size);
memcpy((char *)&bAddr, buffer, sizeof(bAddr));
sockaddr_in *bAddr_in = (sockaddr_in *)&bAddr;
printf("I am A, I recv B is: %s:%d\n", inet_ntoa(bAddr_in->sin_addr), ntohs(bAddr_in->sin_port));
getsockname(sock, (sockaddr *)&t_addr, &t_len);
printf("%s:%d\n", inet_ntoa(t_addr.sin_addr), ntohs(t_addr.sin_port));
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "hello I am A, nice to meet you B!");
// for(int i=0;i!=105;i++)
sendto(sock, buffer, sizeof(buffer), 0, &bAddr, sizeof(bAddr));
getsockname(sock, (sockaddr *)&t_addr, &t_len);
printf("%s:%d\n", inet_ntoa(t_addr.sin_addr), ntohs(t_addr.sin_port));
printf("say hello to B done!\n");
fflush(stdout);
memset(buffer, 0, sizeof(buffer));
recvfrom(sock, buffer, BUF_SIZE, 0, &bAddr, &sockaddr_size);
getsockname(sock, (sockaddr *)&t_addr, &t_len);
printf("%s:%d\n", inet_ntoa(t_addr.sin_addr), ntohs(t_addr.sin_port));
printf("recvfrom B:\n");
printf("%s\n", buffer);
fflush(stdout);
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
return 0;
}
b.cpp
#include <stdio.h>
#include <iostream>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#define sendto(a, b, c, d, e, f) sendto(a, b, c, d, e, f)
#define recvfrom(a, b, c, d, e, f) recvfrom(a, b, c, d, e, f)
#else
#define sendto(a, b, c, d, e, f) sendto(a, b, c, d, e, (socklen_t)f)
#define recvfrom(a, b, c, d, e, f) recvfrom(a, b, c, d, e, (socklen_t *)f)
#endif
#define SPORT 9999
#define BUF_SIZE 100
#define SERVER_IP "127.0.0.1"
using namespace std;
int main(){
#ifdef _WIN32
WSADATA wsaData;
WSAStartup( MAKEWORD(2, 2), &wsaData);
#endif
//创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
//填写服务器地址信息
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr)); //每个字节都用0填充
servAddr.sin_family = PF_INET;
servAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
servAddr.sin_port = htons(SPORT);
//向服务器发送自己的ip和端口
char buffer[BUF_SIZE]="hello I am B";//缓冲区
sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
sockaddr sAddr, aAddr;
int sockaddr_size = sizeof(sockaddr);
memset(buffer, 0, sizeof(buffer));
int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &sAddr, &sockaddr_size);
memcpy((char *)&aAddr, buffer, sizeof(aAddr));
sockaddr_in *aAddr_in = (sockaddr_in *)&aAddr;
printf("I am B, I recv A is: %s:%d\n", inet_ntoa(aAddr_in->sin_addr), ntohs(aAddr_in->sin_port));
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "hello I am B, nice to meet you too A!");
sendto(sock, buffer, sizeof(buffer), 0, &aAddr, sizeof(aAddr));
printf("say hello to A done!\n");
fflush(stdout);
memset(buffer, 0, sizeof(buffer));
recvfrom(sock, buffer, BUF_SIZE, 0, &aAddr, &sockaddr_size);
printf("recvfrom A:\n");
printf("%s\n", buffer);
fflush(stdout);
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
return 0;
}
makefile
all:s a b
s:s.cpp
g++ -o s s.cpp -l wsock32 -l stdc++
a:a.cpp
g++ -o a a.cpp -l wsock32 -l stdc++
b:b.cpp
g++ -o b b.cpp -l wsock32 -l stdc++
clean:
rm *.o *.exe