Skip to content

Commit e503ed3

Browse files
authored
Update main.cpp
1 parent f863882 commit e503ed3

File tree

1 file changed

+191
-5
lines changed

1 file changed

+191
-5
lines changed

main.cpp

Lines changed: 191 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
#include "log.h"
33
#include "git_version.h"
44
#include "fd_manager.h"
5+
#define DOMAIN_MAX_LEN 64
6+
// 跨平台多进程支持
7+
#ifdef _WIN32
8+
#include <windows.h>
9+
#else
10+
#include <unistd.h>
11+
#include <sys/wait.h>
12+
#endif
513

614
using namespace std;
715

@@ -1059,6 +1067,107 @@ int unit_test()
10591067
return 0;
10601068
}
10611069

1070+
int resolve_ipv6(char *domain, char *addr) {
1071+
struct addrinfo hints, *res;
1072+
int err;
1073+
1074+
#ifdef _WIN32
1075+
WSADATA wsaData;
1076+
// 初始化 Winsock
1077+
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
1078+
fprintf(stderr, "WSAStartup failed\n");
1079+
return -1;
1080+
}
1081+
#endif
1082+
1083+
// 清空 hints 结构体并设置为查询 IPv6
1084+
memset(&hints, 0, sizeof(hints));
1085+
hints.ai_family = AF_INET6; // 设置为 IPv6
1086+
1087+
// 调用 getaddrinfo 进行解析
1088+
err = getaddrinfo(domain, NULL, &hints, &res);
1089+
if (err != 0) {
1090+
fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err));
1091+
#ifdef _WIN32
1092+
WSACleanup(); // 清理 Winsock
1093+
#endif
1094+
return -1;
1095+
}
1096+
1097+
// 将解析出的 IPv6 地址转换为字符串格式
1098+
if (res != NULL) {
1099+
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
1100+
inet_ntop(AF_INET6, &ipv6->sin6_addr, addr, INET6_ADDRSTRLEN);
1101+
}
1102+
1103+
// 释放内存
1104+
freeaddrinfo(res);
1105+
1106+
#ifdef _WIN32
1107+
WSACleanup(); // 清理 Winsock
1108+
#endif
1109+
1110+
return 0;
1111+
}
1112+
1113+
#ifdef _WIN32
1114+
// Windows 平台的子进程创建函数
1115+
void create_child_process(const char *program_name, const char *addr, u32_t port, HANDLE job_handle, HANDLE hPipeWrite) {
1116+
// 创建命令行参数
1117+
char cmd[256];
1118+
snprintf(cmd, sizeof(cmd), "%s -l 127.0.0.1:%d -r [%s]:%d -u", program_name, port, addr, port);
1119+
1120+
// 转换为宽字符
1121+
wchar_t wcmd[256];
1122+
MultiByteToWideChar(CP_UTF8, 0, cmd, -1, wcmd, 256);
1123+
1124+
// 设置启动信息,重定向子进程的 stdout 到管道的写端
1125+
STARTUPINFOW si = {sizeof(si)};
1126+
PROCESS_INFORMATION pi = {0};
1127+
si.hStdOutput = hPipeWrite; // 将子进程的 stdout 重定向到管道
1128+
si.dwFlags |= STARTF_USESTDHANDLES;
1129+
1130+
// 启动子进程
1131+
if (!CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
1132+
fprintf(stderr, "Failed to create process for port %d. Error: %lu\n", port, GetLastError());
1133+
exit(1);
1134+
}
1135+
1136+
// 将子进程添加到 Job Object 中
1137+
if (!AssignProcessToJobObject(job_handle, pi.hProcess)) {
1138+
fprintf(stderr, "Failed to assign process to job object. Error: %lu\n", GetLastError());
1139+
exit(1);
1140+
}
1141+
1142+
// 确保子进程句柄关闭,避免资源泄露
1143+
CloseHandle(pi.hProcess);
1144+
CloseHandle(pi.hThread);
1145+
}
1146+
#else
1147+
// Unix/Linux 平台的子进程创建函数
1148+
void create_child_process(const char *program_name, const char *addr,int port) {
1149+
// 未实现!!!
1150+
// 相信会玩Linux的也不差这点命令执行功底吧。。
1151+
pid_t pid = fork();
1152+
if (pid == -1) {
1153+
perror("fork failed");
1154+
exit(1);
1155+
} else if (pid == 0) {
1156+
// 子进程
1157+
printf("Child process started for port %s\n", port);
1158+
char * argv = malloc(sizeof(char)*1024);
1159+
sprintf(argv,"%s -l 127.0.0.1:%d -r [%s]:%d -u",program_name,port,port,addr,port);
1160+
execlp(program_name, program_name, port, NULL);
1161+
// 如果 execlp 返回,说明失败
1162+
perror("execlp failed");
1163+
exit(1);
1164+
} else {
1165+
// 父进程保存子进程 PID,以便稍后终止
1166+
printf("Child process PID: %d\n", pid);
1167+
}
1168+
}
1169+
#endif
1170+
10621171
int main(int argc, char *argv[])
10631172
{
10641173
init_ws();
@@ -1089,9 +1198,86 @@ int main(int argc, char *argv[])
10891198
assert(sizeof(i32_t)==4);
10901199
dup2(1, 2); //redirect stderr to stdout
10911200
int i, j, k;
1092-
process_arg(argc,argv);
1093-
1094-
event_loop();
1095-
1096-
return 0;
1201+
1202+
// 定义默认参数,你可以在这里完成你的自定义,比如默认域名或端口
1203+
const char * defaultDomain = "kore.host";
1204+
u32_t port1 = 10999;
1205+
u32_t port2 = 10998;
1206+
// start --------------
1207+
char *domain;
1208+
// 中文输出 设置控制台编码UTF-8
1209+
SetConsoleOutputCP(CP_UTF8);
1210+
if(argc <3){ // 主进程逻辑
1211+
puts("----------*****----------");
1212+
puts("这是一个在原版(wangyu-/tinyPortMapper)基础上修改过的程序,目的是提供饥荒联机版的IPv6端口映射方式完成直连,以显著降低联机时延。\n");
1213+
puts("你可以使用原版的参数列表,也可以使用快捷映射命令:./dstClientPortMapper.exe [domain] ");
1214+
puts("如果你双击直接运行(不输入参数),则将使用域名 \"kore.host\" 作为缺省参数。");
1215+
puts("该命令将会把域名的10999和10998端口映射到本地127.0.0.1地址上。进入饥荒联机版以后可以按'~'唤出控制台,输入 c_connect(\"127.0.0.1\") 然后回车即可\n");
1216+
puts("直接关闭窗口即可结束映射。感谢你的使用。");
1217+
puts("如果有侵权问题,请联系我。https://github.com/binbla\n");
1218+
puts("如果你想要完成自己的修改,自己读源码吧。😋\n");
1219+
puts("----------*****----------");
1220+
if(argc == 1){
1221+
domain = (char*)malloc(sizeof(char)*DOMAIN_MAX_LEN);
1222+
strcpy(domain,defaultDomain);// 默认域名
1223+
printf("use default domain: %s\n",defaultDomain);
1224+
}else{
1225+
domain = argv[1];
1226+
}
1227+
// 域名解析
1228+
char addr[INET6_ADDRSTRLEN];
1229+
if (resolve_ipv6(domain, addr) == 0) {
1230+
printf("IPv6 address for %s: %s\n", domain, addr);
1231+
} else {
1232+
printf("Failed to resolve IPv6 address for %s\n", domain);
1233+
exit(-1);
1234+
}
1235+
printf("Parent process started.\n");
1236+
#ifdef _WIN32 //windows 逻辑
1237+
// 创建一个 Job Object 来管理所有子进程
1238+
HANDLE job_handle = CreateJobObject(NULL, NULL);
1239+
if (job_handle == NULL) {
1240+
fprintf(stderr, "Failed to create job object. Error: %lu\n", GetLastError());
1241+
exit(1);
1242+
}
1243+
// 创建管道,父进程从中读取数据
1244+
HANDLE hPipeRead, hPipeWrite;
1245+
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
1246+
if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) {
1247+
fprintf(stderr, "CreatePipe failed\n");
1248+
exit(1);
1249+
}
1250+
// 创建子进程并将它们添加到 Job Object 中
1251+
create_child_process(argv[0], addr, port1, job_handle, hPipeWrite);
1252+
create_child_process(argv[0], addr, port2, job_handle, hPipeWrite);
1253+
// 父进程从管道读取并输出
1254+
CloseHandle(hPipeWrite); // 关闭管道的写端
1255+
char buf[256];
1256+
DWORD bytesRead;
1257+
while (ReadFile(hPipeRead, buf, sizeof(buf) - 1, &bytesRead, NULL) && bytesRead > 0) {
1258+
buf[bytesRead] = '\0'; // 添加 null 终止符
1259+
printf("%s", buf); // 打印子进程的输出
1260+
}
1261+
1262+
// 父进程等待子进程退出
1263+
WaitForSingleObject(job_handle, INFINITE);
1264+
// 清理 Job Object
1265+
CloseHandle(job_handle);
1266+
#else //unix 逻辑
1267+
// 创建两个子进程
1268+
create_child_process(argv[0], addr,port1);
1269+
sleep(1);
1270+
create_child_process(argv[0], addr,port2);
1271+
// 父进程等待所有子进程退出(通过发送信号终止)
1272+
// 父进程等待子进程(仅 Unix/Linux 需要,Windows 子进程生命周期与父进程绑定)
1273+
while (wait(NULL) > 0); // 等待所有子进程退出
1274+
#endif
1275+
printf("Parent process exiting\n");
1276+
return 0;
1277+
}else{// 子进程逻辑
1278+
printf("Child process started\n");
1279+
process_arg(argc,argv);
1280+
event_loop();
1281+
return 0;
1282+
}
10971283
}

0 commit comments

Comments
 (0)