NAT 관통 기술 상세 해석 (udp 구멍 뚫 기 정수 부 코드)
만약 당신 이 nat 관통 기술 의 상세 한 해석 점 이 필요 하 다 면 여기: nat 관통 분석
필요 한 장치:
알 고 있 는 외부 네트워크 서버 S (ip + port), 서로 다른 외부 네트워크 에 있 는 클 라 이언 트 A, B
우선 udp 가 구멍 을 뚫 는 절 차 를 알 아야 합 니 다.
1. A 클 라 이언 트 는 S, B 클 라 이언 트 는 서버 S 에 메 시 지 를 보낸다.
2. S 전송 A 의 ip + port (여 기 는 A 의 외부 네트워크 ip + port, nat 전송 기 에 있 음) 클 라 이언 트 B, S 전송 B 의 ip + port 를 클 라 이언 트 A 에 게 전달 합 니 다.
이렇게 A, B 는 모두 엔 드 의 ip + port 를 알 게 되 었 다.
3. A 가 B 에 게 메 시 지 를 보 내 면 B 는 이 메 시 지 를 차단 하지만 A 의 nat 맵 에 맵 을 추가 하여 A 가 B 로부터 메 시 지 를 받 을 수 있 도록 합 니 다.A 에 구멍 을 뚫다
B-->A。
4. B 는 A 에 게 메 시 지 를 보 냅 니 다. 여 기 는 절차 3A 가 이 메 시 지 를 받 을 수 있 기 때문에 B 의 nat 맵 에 맵 을 추가 하여 B 가 A 에서 온 메 시 지 를 받 을 수 있 도록 합 니 다.B 에서
구멍 뚫 기, A - > B.
5. 여기까지 A, B 홀 성공.
저 는 이 지식 을 공부 할 때 인터넷 의 사례 와 해석 을 보면 대부분이 서로 전달 되 고 표현 이 잘 되 지 않 습 니 다. 코드 인 스 턴 스 를 가 져 와 서 사용 하 는 것 도 문제 가 많 고 실제 문 제 를 해결 하지 못 하기 때문에 자신 도 엄 격 히 요구 하고 문제 가 있 는 코드 를 붙 이지 못 합 니 다.
다음은 코드 입 니 다. A 반사 B 의 소식 을 실현 합 니 다.
서버 S 의 코드:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// A ip port B, B ip port A
//B A A, A B , A nat B ,
// B A
// , A B B, B A , A
// B , A B 。 p2p
/* S AB , A S B S , udp 。 */
#define ERR_EXIT(m)\
do{\
perror(m);\
exit(1);\
}while(0)
/* ip+port */
typedef struct{
struct in_addr ip;
int port;
}clientInfo;
int main()
{
/* , ip+port */
clientInfo info[2];
/* */
/* char ch; */
char str[10] = {0};
/* udp socket */
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
ERR_EXIT("SOCKET");
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0");
serveraddr.sin_port = htons(8888);
serveraddr.sin_family = AF_INET;
int ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if(ret == -1)
ERR_EXIT("BIND");
/* */
while(1)
{
bzero(info, sizeof(clientInfo)*2);
/* ip+port */
socklen_t addrlen = sizeof(struct sockaddr_in);
/* recvfrom(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&serveraddr, &addrlen); */
recvfrom(sockfd, str, sizeof(str), 0, (struct sockaddr *)&serveraddr, &addrlen);
memcpy(&info[0].ip, &serveraddr.sin_addr, sizeof(struct in_addr));
info[0].port = serveraddr.sin_port;
printf("A client IP:%s \tPort:%d creat link OK!
", inet_ntoa(info[0].ip), ntohs(info[0].port));
/* recvfrom(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&serveraddr, &addrlen); */
recvfrom(sockfd, str, sizeof(str), 0, (struct sockaddr *)&serveraddr, &addrlen);
memcpy(&info[1].ip, &serveraddr.sin_addr, sizeof(struct in_addr));
info[1].port = serveraddr.sin_port;
printf("B client IP:%s \tPort:%d creat link OK!
", inet_ntoa(info[1].ip), ntohs(info[1].port));
/* ip+port */
printf("start informations translation...
");
serveraddr.sin_addr = info[0].ip;
serveraddr.sin_port = info[0].port;
sendto(sockfd, &info[1], sizeof(clientInfo), 0, (struct sockaddr *)&serveraddr, addrlen);
serveraddr.sin_addr = info[1].ip;
serveraddr.sin_port = info[1].port;
sendto(sockfd, &info[0], sizeof(clientInfo), 0, (struct sockaddr *)&serveraddr, addrlen);
printf("send informations successful!
");
}
return 0;
}
클 라 이언 트 A 의 코드:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* */
#define ERR_EXIT(m)\
do{\
perror(m); \
exit(1);\
}while(0)
typedef struct{
struct in_addr ip;
int port;
}clientInfo;
/* udp */
void echo_ser(int sockfd, struct sockaddr* addr, socklen_t *len)
{
printf("start recv B data...
");
char buf[1024];
while(1)
{
bzero(buf, sizeof(buf));
// B
recvfrom(sockfd, buf, sizeof(buf)-1, 0, addr, len);
printf("%s
", buf);
// B
printf("send data to B ...
");
sendto(sockfd, buf, sizeof(buf)-1, 0, addr, sizeof(struct sockaddr_in));
buf[strlen(buf)] = '\0';
if(strcmp(buf, "exit") == 0)
break;
}
}
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
ERR_EXIT("SOCKET");
//
char ch = 'a';
clientInfo info;
socklen_t addrlen = sizeof(struct sockaddr_in);
bzero(&info, sizeof(info));
struct sockaddr_in clientaddr;
memset(&clientaddr, 0, sizeof(clientaddr));
//
clientaddr.sin_port = htons(8888);
// ip , ip , ip 。
clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
clientaddr.sin_family = AF_INET;
/* S */
sendto(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&clientaddr, sizeof(struct sockaddr_in));
/* B ip+port */
printf("send success
");
recvfrom(sockfd, &info, sizeof(clientInfo), 0, (struct sockaddr *)&clientaddr, &addrlen);
printf("IP: %s\tPort: %d
", inet_ntoa(info.ip), ntohs(info.port));
clientaddr.sin_addr = info.ip;
clientaddr.sin_port = info.port;
sendto(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&clientaddr, sizeof(struct sockaddr_in));
echo_ser(sockfd, (struct sockaddr *)&clientaddr, &addrlen);
close(sockfd);
return 0;
}
클 라 이언 트 B 코드:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* */
#define ERR_EXIT(m)\
do{\
perror(m); \
exit(1);\
}while(0)
typedef struct{
struct in_addr ip;
int port;
}clientInfo;
/* udp */
void echo_ser(int sockfd, struct sockaddr* addr, socklen_t *len)
{
char buf[1024];
while(1)
{
bzero(buf, sizeof(buf));
printf(">> ");
fflush(stdout);
fgets(buf, sizeof(buf)-1, stdin);
// A
sendto(sockfd, buf, strlen(buf), 0, addr, sizeof(struct sockaddr_in));
// A
bzero(buf, sizeof(buf));
printf("start recv A data...
");
recvfrom(sockfd, buf, sizeof(buf)-1, 0, addr, len);
printf("%s
", buf);
buf[strlen(buf)] = '\0';
if(strcmp(buf, "exit") == 0)
break;
}
}
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
ERR_EXIT("SOCKET");
//
char ch = 'a';
/* char str[] = "abcdefgh"; */
clientInfo info;
socklen_t addrlen = sizeof(struct sockaddr_in);
bzero(&info, sizeof(info));
struct sockaddr_in clientaddr, serveraddr;
/* ip+port */
/* memset(&clientaddr, 0, sizeof(clientaddr)); */
/* clientaddr.sin_port = htons(8888); */
/* clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
/* clientaddr.sin_family = AF_INET; */
/* */
memset(&clientaddr, 0, sizeof(clientaddr));
// port
serveraddr.sin_port = htons(4399);
// ip, ip , ip ip
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
serveraddr.sin_family = AF_INET;
/* S */
sendto(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in));
/* sendto(sockfd, str, sizeof(str), 0, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in)); */
/* B ip+port */
printf("send success
");
recvfrom(sockfd, &info, sizeof(clientInfo), 0, (struct sockaddr *)&serveraddr, &addrlen);
printf("IP: %s\tPort: %d
", inet_ntoa(info.ip), ntohs(info.port));
serveraddr.sin_addr = info.ip;
serveraddr.sin_port = info.port;
sendto(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in));
echo_ser(sockfd, (struct sockaddr *)&serveraddr, &addrlen);
close(sockfd);
return 0;
}
상기 코드 는 본인 의 디 버 깅 테스트 를 거 친 후에 크로스 오 버 네트워크 통신 을 실현 할 수 있 고 아무런 문제 가 없습니다.
이 항목 을 쓸 때 발생 하 는 문제:
1. 처음에 제 로 컬 클 라 이언 트 는 서버 S 에 연결 되 지 않 았 습 니 다. 코드 가 로 컬 테스트 에 성공 한 상황 에서 도 제 클 라 우 드 서버 가 지정 한 감청 포트 8888 이 열 리 지 않 고 외부 메 시 지 를 받 지 않 았 기 때 문 입 니 다.포트 를 열 어 성공 적 으로 해결 하 다.
2. 서버 S 는 AB 의 연결 메 시 지 를 받 을 수 있 고 AB 의 ip 과 port 를 상대방 에 게 전달 할 수 있 으 며 AB 도 상대방 의 ip + port 를 얻 을 수 있 습 니 다. 그러나 B 가 A 에 게 메 시 지 를 보 낼 때 A 는 while (1) 순환 중의 첫 번 째 recvfrom 에 막 혔 습 니 다. 왜 일 까요?
이 유 는 구멍 을 뚫 는 과정 에서 제 가 절차 3, 4 가 빠 졌 기 때 문 입 니 다. B 가 A 에 게 메 시 지 를 보 내 면 A 가 B 의 메 시 지 를 차단 하기 때 문 입 니 다.이때 A 도 B 에 게 메 시 지 를 보 내야 한다.
그래서 저 는 원래 A, B 코드 였 어 요.
echo_ser(sockfd, (struct sockaddr *)&serveraddr, &addrlen);
앞 에 한 마디 를 덧 붙 였 다.
sendto(sockfd, &ch, sizeof(ch), 0, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in));
이렇게 하면 A 든 B 든 이 문 구 를 먼저 집행 하면 구멍 을 뚫 는 데 성공 할 수 있다. 만약 에 이 문장 앞 에 sleep (5) 를 한 마디 넣 으 면 구멍 을 뚫 는 과정 을 느 낄 수 있다.
여기까지 문 제 를 해결 하고 기대 하 는 기능 을 실현 하 였 으 니 나의 글 이 너 에 게 도움 이 되 기 를 바란다.표현 이 명확 하지 않 으 면 질문 을 환영 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
UDP 체크섬 이해의 책에서 공부하고 있었습니다만, UDP의 체크섬의 부분이 약간 어려웠으므로 자신 나름대로 정리해 아웃풋 합니다. 소스 포트 번호 대상 포트 번호 체크섬 체크섬 이외의 설명은 불필요하다고 생각하므로 생략합니다. 체크...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.