C语言Windows公网转发工具(内网穿透)

C语言写的内网穿透工具,将家用电脑的服务映射到公网。

公网服务器实现原理:

        1.创建两个socket(两个不同的端口)分别监听私网服务器的连接;

        2.等待私网服务器连接;

        3.等待客户端连接,收到客户端的连接请求立即发送消息通知私网服务器

        4.等待私网服务器发起连接

        5.创建独立线程将客户端的数据与私网服务器的数据相互转发。

运行于公网程序源码

#include <stdio.h>
#include <windows.h>
#include <thread>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

#define Link_server_port 4001	//监听服务器的端口
#define Link_user_port 4002	//监听用户(客户端)端口

//数据转发函数
void s1_s2(SOCKET sock1, SOCKET sock2);

//通道维护函数
void link_hello(SOCKET sock);
void link_chek(SOCKET sock);
int main()
{
	//初始化网络库
	WSADATA vs;
	WSAStartup(MAKEWORD(2, 2), &vs);

	//创建监听私网服务器socket与网络信息
	SOCKET listen_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	SOCKADDR_IN listen_server_net;
	listen_server_net.sin_family = AF_INET;
	listen_server_net.sin_addr.S_un.S_addr = INADDR_ANY;
	listen_server_net.sin_port = htons(4001);

	//绑定socket与网络参数
	if (::bind(listen_server, (SOCKADDR*)&listen_server_net, sizeof(listen_server_net)) == SOCKET_ERROR)
	{
		printf("绑定4001端口错误\n"); Sleep(2000); exit(-1);
	}

	//监听链接
	if (listen(listen_server, 5) == SOCKET_ERROR)
	{
		printf("监听4001端口错误\n"); Sleep(2000); exit(-1);
	}

	//创建监听客户端socket与网络信息
	SOCKET listen_user = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	SOCKADDR_IN listen_user_net;
	listen_user_net.sin_family = AF_INET;
	listen_user_net.sin_addr.S_un.S_addr = INADDR_ANY;
	listen_user_net.sin_port = htons(4002);

	//绑定socket与网络参数
	if (::bind(listen_user, (SOCKADDR*)&listen_user_net, sizeof(listen_user_net)) == SOCKET_ERROR)
	{
		printf("绑定4002端口错误\n"); Sleep(2000); exit(-1);
	}

	//监听链接
	if (listen(listen_user, 5) == SOCKET_ERROR)
	{
		printf("监听4002端口错误\n"); Sleep(2000); exit(-1);
	}

	//等待服务器连接
	printf("等待内网服务器连接\n");
	SOCKET to_server;
	SOCKADDR_IN tmp;
	int j = sizeof(tmp);
	do
	{
		to_server = accept(listen_server, (SOCKADDR*)&tmp, &j);
	} while (to_server <= 0);
	printf("内网服务器连接成功:%s \n", inet_ntoa(tmp.sin_addr));

	//通道维护
	thread TD(link_hello, to_server);
	TD.detach();
	thread TD2(link_chek, to_server);
	TD2.detach();

	//循环等待用户链接
	while (true)
	{
		SOCKET user = accept(listen_user, (SOCKADDR*)&tmp, &j);
		if (user<0) continue;
		printf("用户连接成功:%s\n", inet_ntoa(tmp.sin_addr));

		//通知服务器有新的链接
		send(to_server, "new_connet", 20, 0);

		//等待服务器发起新链接
		printf("等待服务器响应\n");
		SOCKET server = accept(listen_server, NULL, NULL);
		if (server < 0) continue;
		printf("服务器已响应\n");

		//两个socket加入到相互转发线程
		thread t1(s1_s2, user, server);
		t1.detach();

		thread t2(s1_s2, server, user);
		t2.detach();
	}
	closesocket(listen_server);
	closesocket(listen_user);
	WSACleanup();
	return 0;
}

//数据转发函数
void s1_s2(SOCKET sock1, SOCKET sock2)
{
	while (1)
	{
		char data[1024] = { 0 };
		int ret = recv(sock1, data, 1024, 0);
		if (ret > 0)
		{
			send(sock2, data, ret, 0);
		}
		if (ret == 0)
		{
			closesocket(sock1);
			closesocket(sock2);
			return;
		}
		if (ret < 0)
		{
			closesocket(sock1);
			return;
		}
	}
}

//通道维护
void link_hello(SOCKET sock)
{
	while (1)
	{
		send(sock, "hello pack", 11, 0);
		Sleep(10000);
	}
}

void link_chek(SOCKET sock)
{
	while (1)
	{
		char data[128] = { 0 };
		int ret = recv(sock, data, 128, 0);
		if (ret < 1)
		{
			closesocket(sock);
			WSACleanup();
			exit(0);
		}
	}
}

私网服务器实现原理

        1.创建socket连接公网服务器,等待新客户连接申请

        2.收到新客户连接申请,向公网服务器发起新的连接

        3.创建socket向本地服务端口发起连接

        4.创建独立线程将服务端口数据与客户端数据相互转发

运行在内网服务器代码

#include <stdio.h>
#include <windows.h>
#include <string>
#include <thread>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

#define public_ip "103.222.189.25"	//公网服务器IP
#define public_port 4001	//公网服务器端口
#define local_ip "127.0.0.1"	//本地服务器IP
#define local_port 80	//	本地服务器端口

int num = 0;
//数据转发函数
void s1_s2(SOCKET sock1, SOCKET sock2);

int main()
{
	//初始化网络参数
	WSADATA vs;
	WSAStartup(MAKEWORD(2, 2), &vs);

	//创建链接公网服务的socket与网络信息
	SOCKET listen_IP = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	SOCKADDR_IN IP_net;
	IP_net.sin_family = AF_INET;
	IP_net.sin_addr.S_un.S_addr = inet_addr(public_ip);
	IP_net.sin_port = htons(public_port);

	//链接公网服务器
	if (connect(listen_IP, (SOCKADDR*)&IP_net, sizeof(IP_net)) == SOCKET_ERROR)
	{
		printf("链接公网服务器失败\n"); Sleep(2000); exit(-1);
	}
	printf("链接公网服务器成功\n");

	//创建服务器信息
	SOCKADDR_IN server_net;
	server_net.sin_family = AF_INET;
	server_net.sin_addr.S_un.S_addr = inet_addr(local_ip);
	server_net.sin_port = htons(local_port);

	//等待公网服务器发送消息
	while (true)
	{
		while (true)
		{
			char data[128] = { 0 };
			int ret = recv(listen_IP, data, 128, 0);
			if (ret == 11 && !strcmp(data, "hello pack"))
			{
				send(listen_IP, "hello pack", 11, 0);
				continue;
			}
			if (ret == 20 && !strcmp(data, "new_connet"))
			{
				printf("收到新用户链接请求\n");
				//有新的用户链接,向公网服务器发起一个新的链接
				SOCKET to_user = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
				if (connect(to_user, (SOCKADDR*)&IP_net, sizeof(IP_net)) == SOCKET_ERROR)
				{
					closesocket(to_user);
					continue;
				}
				printf("向公网服务器发起新链接成功\n");

				//向服务器发起链接
				SOCKET to_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
				if (connect(to_server, (SOCKADDR*)&server_net, sizeof(server_net)) == SOCKET_ERROR)
				{
					printf("链接本机服务出错\n ");
					closesocket(to_user);
					continue;
				}
				printf("连接本机服务成功\n");

				//数据转发线程
				thread t1(s1_s2, to_user, to_server);
				t1.detach();
				thread t2(s1_s2, to_server, to_user);
				t2.detach();
			}
			if (ret <= 0)
			{
				closesocket(listen_IP);
				printf("服务器关闭连接\n");
				Sleep(1000);
				exit(0);
			}
		}
	}
}
//数据转发函数
void s1_s2(SOCKET sock1, SOCKET sock2)
{
	while (1)
	{
		char data[1024] = { 0 };
		int ret = recv(sock1, data, 1024, 0);
		if (ret > 0)
		{
			num += ret;
			send(sock2, data, ret, 0);
		}
		if (ret == 0)
		{
			closesocket(sock1);
			closesocket(sock2);
			return;
		}
		if (ret < 0)
		{
			closesocket(sock1);
			return;
		}
	}
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很高兴为您解答,关于用C语言实现内网穿透的代码,可以参考以下示例代码: #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> int main() { int sockfd, port; struct sockaddr_in serv_addr; struct hostent *server; int bytes_recvd; char buffer[1024]; // Create socket sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { printf("socket() failed!"); exit(1); } // Connect to server port = 80; server = gethostbyname("www.example.com"); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf("connect() failed!"); exit(1); } // Receive data bytes_recvd = recv(sockfd, buffer, 1024, 0); if (bytes_recvd < 0) { printf("recv() failed!"); exit(1); } else { buffer[bytes_recvd] = '\0'; printf("Data received: %s", buffer); } // Close socket close(sockfd); return 0; } ### 回答2: 内网穿透是一种技术,它通过将内网的数据包通过公网中转,实现内网与外网之间的通信。要用C语言实现内网穿透的代码,可以借助第三方库例如libevent来简化网络编程。 首先,我们需要建立一个服务器和客户端来连接内外网。服务器位于外网,并监听来自客户端的连接请求。客户端位于内网,连接到服务器,将内网数据包通过服务器转发出去。 服务器端代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <event2/event.h> void client_read_cb(struct bufferevent* bev, void* ctx) { struct evbuffer* input = bufferevent_get_input(bev); struct evbuffer* output = bufferevent_get_output(bev); size_t len = evbuffer_get_length(input); if (len > 0) { // 处理接收到的从客户端发送的数据 // 然后将数据发送给目标服务器 evbuffer_add_buffer(output, input); } } void server_accept_cb(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* addr, int socklen, void* ctx) { struct event_base* base = ctx; struct bufferevent* bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); // 设置客户端的读回调函数 bufferevent_setcb(bev, client_read_cb, NULL, NULL, NULL); bufferevent_enable(bev, EV_READ | EV_WRITE); } int main() { struct event_base* base; struct evconnlistener* listener; struct sockaddr_in server_addr; base = event_base_new(); if (!base) { printf("Could not initialize libevent!\n"); return -1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(1234); // 设置监听端口 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); listener = evconnlistener_new_bind(base, server_accept_cb, (void*)base, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (!listener) { printf("Could not create a listener!\n"); return -1; } event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); return 0; } ``` 客户端代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <event2/event.h> void server_read_cb(struct bufferevent* bev, void* ctx) { struct evbuffer* input = bufferevent_get_input(bev); struct evbuffer* output = bufferevent_get_output(bev); size_t len = evbuffer_get_length(input); if (len > 0) { // 处理接收到的从服务器发送的数据 // 然后将数据发送给内网目标设备 evbuffer_add_buffer(output, input); } } int main() { struct event_base* base; struct bufferevent* bev; base = event_base_new(); if (!base) { printf("Could not initialize libevent!\n"); return -1; } bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); if (!bev) { printf("Could not create a buffer event!\n"); return -1; } struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = 0; // 任意可用的本地端口 if (bufferevent_socket_connect(bev, (struct sockaddr*)&sin, sizeof(sin)) < 0) { bufferevent_free(bev); printf("Could not connect to the server!\n"); return -1; } bufferevent_setcb(bev, server_read_cb, NULL, NULL, NULL); bufferevent_enable(bev, EV_READ | EV_WRITE); event_base_dispatch(base); bufferevent_free(bev); event_base_free(base); return 0; } ``` 以上示例代码演示了使用C语言实现内网穿透的基本原理。实际应用中可能还需要处理各种网络异常和错误处理,具体实现代码应根据具体需求进行调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值