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
文章目录