环境
公网服务器1台,内网服务器若干。其中一台内网可以和公网连接通信,打算在公网上用socket做端口转发来实现访各台问内网的目的。功能已经实现了(一对一连接),但端口复用问题一直很困惑,请各位帮忙检查一下代码,谢谢
公网代码
// 绑定两个服务器socket
void bind2bind(int port1, int port2)
{
char msgbuf[100];
memset(msgbuf, 0, 100);
sprintf(msgbuf, "[+] 服务器初始化...\r\n");
outprint(msgbuf, strlen(msgbuf));
int fd0, fd1, fd2;
if ((fd0 = create_socket()) == 0) return;
if ((fd1 = create_socket()) == 0) return;
if ((fd2 = create_socket()) == 0) return;
int port0 = 5501;
if (create_server(fd0, port0) == 0)
{
closesocket(fd0);
return;
}
sprintf(msgbuf, "[+] 成功监听通信端口: %d\r\n", port0);
outprint(msgbuf, strlen(msgbuf));
// 创建第一个服务器
if (create_server(fd1, port1) == 0)
{
closesocket(fd1);
return;
}
sprintf(msgbuf, "[+] 成功监听隧道端口: %d\r\n", port1);
outprint(msgbuf, strlen(msgbuf));
// 创建第二个服务器
if (create_server(fd2, port2) == 0)
{
closesocket(fd2);
return;
}
sprintf(msgbuf, "[+] 成功监听上线端口: %d\r\n", port2);
outprint(msgbuf, strlen(msgbuf));
// 等待两端上线
while (1)
{
sprintf(msgbuf, "[%d] 正在建立通信端口: %d\r\n", idx, port0);
outprint(msgbuf, strlen(msgbuf));
struct sockaddr_in client0;
int size0 = sizeof(struct sockaddr);
int sockfd0 = accept(fd0, (struct sockaddr *)&client0, &size0);
sprintf(msgbuf, "[%d] 通信端口连接成功 IP地址: %s\r\n", idx, inet_ntoa(client0.sin_addr));
outprint(msgbuf, strlen(msgbuf));
sprintf(msgbuf, "[%d] 发送idx值: %d\r\n", idx, idx);
outprint(msgbuf, strlen(msgbuf));
char idxbuf[10];
memset(idxbuf, 0, 10);
sprintf(idxbuf, "%d", idx);
int send0 = send(sockfd0, idxbuf, strlen(idxbuf)+1, 0);
if (send0 <= 0)
{
closesocket(sockfd0);
continue;
}
closesocket(sockfd0);
sprintf(msgbuf, "[%d] 正在建立隧道端口: %d\r\n", idx, port1);
outprint(msgbuf, strlen(msgbuf));
struct sockaddr_in client1;
int size1 = sizeof(struct sockaddr);
int sockfd1 = accept(fd1, (struct sockaddr *)&client1, &size1);
sprintf(msgbuf, "[%d] 正在建立上线端口: %d\r\n", idx, port2);
outprint(msgbuf, strlen(msgbuf));
struct sockaddr_in client2;
int size2 = sizeof(struct sockaddr);
int sockfd2 = accept(fd2, (struct sockaddr *)&client2, &size2);
sprintf(msgbuf, "[%d] 通过上线端口连接成功 IP地址: %s\r\n", idx, inet_ntoa(client2.sin_addr));
outprint(msgbuf, strlen(msgbuf));
// socket
transocket sock;
sock.fd1 = sockfd1;
sock.fd2 = sockfd2;
sock.idx = idx;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)transmitdata, (LPVOID)&sock, 0, NULL);
idx++;
}
}
负责通信的内网代码
{
int port0 = 5501;
char msgbuf[100];
memset(msgbuf, 0, 100);
while (1)
{
int sockfd0;
if ((sockfd0 = create_socket()) == 0) return 0;
// 通过5501端口连接服务器
sprintf(msgbuf, "[+] 正在连接服务器 %s:%d\r\n", sConnectHost, port0);
outprint(msgbuf, strlen(msgbuf));
if (client_connect(sockfd0, sConnectHost, port0) == 0)
{
closesocket(sockfd0);
continue;
}
sprintf(msgbuf, "[+] 服务器连接成功\r\n");
outprint(msgbuf, strlen(msgbuf));
// 接收服务器idx值
char idxbuf[10];
memset(idxbuf, 0, 10);
int read0 = recv(sockfd0, idxbuf, 10, 0);
if (read0 > 0)
{
// 在线程内执行conn2conn
int nIdx = atoi(idxbuf);
tranconn2conn conn;
conn.host1 = sConnectHost;
conn.port1 = iConnectPort;
conn.host2 = sTransmitHost;
conn.port2 = iTransmitPort;
conn.idx = nIdx;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)conn2conn, (LPVOID)&conn, 0, NULL);
}
}
closeallfd();
}
// 内网转发数据
void conn2conn(LPVOID data)
{
tranconn2conn *conn = (tranconn2conn *)data;
char msgbuf[100];
memset(msgbuf, 0, 100);
while (1)
{
int sockfd1, sockfd2;
if ((sockfd1 = create_socket()) == 0) return;
if ((sockfd2 = create_socket()) == 0) return;
sprintf(msgbuf, "[%d] 正在连接服务器 %s:%d\r\n", conn->idx, conn->host1, conn->port1);
outprint(msgbuf, strlen(msgbuf));
if (client_connect(sockfd1, conn->host1, conn->port1) == 0)
{
closesocket(sockfd1);
closesocket(sockfd2);
continue;
}
sprintf(msgbuf, "[%d] 服务器连接成功\r\n", conn->idx);
outprint(msgbuf, strlen(msgbuf));
sprintf(msgbuf, "[%d] 正在连接内网 %s:%d\r\n", conn->idx, conn->host2, conn->port2);
outprint(msgbuf, strlen(msgbuf));
if (client_connect(sockfd2, conn->host2, conn->port2) == 0)
{
closesocket(sockfd1);
closesocket(sockfd2);
continue;
}
sprintf(msgbuf, "[%d] 内网连接成功\r\n", conn->idx);
outprint(msgbuf, strlen(msgbuf));
// socket
transocket sock;
sock.fd1 = sockfd1;
sock.fd2 = sockfd2;
sock.idx = conn->idx;
transmitdata(&sock);
}
}
数据转发代码
// 服务器转发数据
void transmitdata(LPVOID data)
{
transocket *sock = (transocket *)data;
// 准备采用select模型
fd_set readfd, writefd;
char read_in1[MAXSIZE], send_out1[MAXSIZE];
char read_in2[MAXSIZE], send_out2[MAXSIZE];
struct sockaddr_in client1, client2;
char host1[20], host2[20], msgbuf[100];
memset(host1, 0, 20);
memset(host2, 0, 20);
memset(msgbuf, 0, 100);
int port1 = 0, port2 = 0;
int structsize1 = sizeof(struct sockaddr);
int structsize2 = sizeof(struct sockaddr);
// 获取第一客户端信息
if (getpeername(sock->fd1, (struct sockaddr *)&client1, &structsize1) < 0)
{
strcpy(host1, "fd1");
}
else
{
strcpy(host1, inet_ntoa(client1.sin_addr));
port1 = ntohs(client1.sin_port);
}
// 获取第二客户端信息
if (getpeername(sock->fd2, (struct sockaddr *)&client2, &structsize2) < 0)
{
strcpy(host2, "fd2");
}
else
{
strcpy(host2, inet_ntoa(client2.sin_addr));
port2 = ntohs(client2.sin_port);
}
sprintf(msgbuf, "[%d] fd1: %d, fd2: %d\r\n", sock->idx, sock->fd1, sock->fd2);
outprint(msgbuf, strlen(msgbuf));
// 输出两个客户端信息
sprintf(msgbuf, "[%d] 建立数据转发走向(%s:%d <-> %s:%d)\r\n", sock->idx, host1, port1, host2, port2);
outprint(msgbuf, strlen(msgbuf));
// 最大检测数目
int maxfd = max(sock->fd1, sock->fd2) + 1;
// 设置检测超时
struct timeval timeset;
timeset.tv_sec = TIMEOUT; // 超时秒数
timeset.tv_usec = 0; // 超时微秒
// 位模式清零
memset(send_out1, 0, MAXSIZE);
memset(send_out2, 0, MAXSIZE);
// 可读长度
int totalread1 = 0, totalread2 = 0;
while (1)
{
// 采用select异步模型
FD_ZERO(&readfd);
FD_ZERO(&writefd);
// 添加到fd集合
FD_SET(sock->fd1, &readfd);
FD_SET(sock->fd1, &writefd);
FD_SET(sock->fd2, &readfd);
FD_SET(sock->fd2, &writefd);
// 第一个参数会被系统忽略掉
int result = select(maxfd, &readfd, &writefd, NULL, ×et);
if ((result < 0) && (errno != EINTR))
{
// 程序出错
sprintf(msgbuf, "[%d] Error: select函数出错\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
break;
}
else if (result == 0)
{
// 等待超时
sprintf(msgbuf, "[%d] Error: select函数等待超时\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
continue;
}
// fd1可读, 只要可读, 一次即可读取完整, 无需while循环
if (FD_ISSET(sock->fd1, &readfd) && totalread1 < MAXSIZE)
{
int read1 = recv(sock->fd1, read_in1, MAXSIZE - totalread1, 0);
if (read1 == 0 || (read1 < 0 && errno != EINTR))
{
sprintf(msgbuf, "[%d] Error: 读取fd1出错\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
break;
}
// 改变fd1的发送缓冲区和他的大小(接了就要发嘛)
memcpy(send_out1 + totalread1, read_in1, read1);
sprintf(msgbuf, "[%d] fd1成功在地址: %16s:%d上面读取%d字节\r\n", sock->idx, host1, port1, read1);
outprint(msgbuf, strlen(msgbuf));
totalread1 += read1;
memset(read_in1, 0, MAXSIZE);
}
// fd2可写
if (FD_ISSET(sock->fd2, &writefd))
{
int err = 0;
int sendcount1 = 0;
// 发送的话可能一次发不完(数据包过大)
while (totalread1 > 0)
{
int send1 = send(sock->fd2, send_out1+sendcount1, totalread1, 0);
if (send1 == 0 || (send1 < 0 && errno != EINTR))
{
sprintf(msgbuf, "[%d] Error: 写入fd2出错\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
err = 1;
break;
}
if ((send1 < 0) && (errno == ENOSPC)) break;
// 改变缓冲区大小
sendcount1 += send1;
totalread1 -= send1;
sprintf(msgbuf, "[%d] fd2成功在地址: %16s:%d上面发送%d字节\r\n", sock->idx, host2, port2, send1);
outprint(msgbuf, strlen(msgbuf));
}
// 检验出错
if (err == 1) break;
// 如果发送了数据, 并且没有发送干净
if ((totalread1 > 0) && (sendcount1 > 0))
{
// 理论上下面两行永远不会执行
memcpy(send_out1, send_out1 + sendcount1, totalread1);
memset(send_out1 + totalread1, 0, MAXSIZE - totalread1);
}
else
{
memset(send_out1, 0, MAXSIZE);
}
}
// fd2可读, 只要可读, 一次即可读取完整, 无需while循环
if (FD_ISSET(sock->fd2, &readfd) && totalread2 < MAXSIZE)
{
int read2 = recv(sock->fd2, read_in2, MAXSIZE - totalread2, 0);
if (read2 == 0 || (read2 < 0 && errno != EINTR))
{
sprintf(msgbuf, "[%d] Error: 读取fd2出错\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
break;
}
// 接了就立即发出去
memcpy(send_out2 + totalread2, read_in2, read2);
sprintf(msgbuf, "[%d] fd2成功在地址: %16s:%d上面读取%d字节\r\n", sock->idx, host2, port2, read2);
outprint(msgbuf, strlen(msgbuf));
totalread2 += read2;
memset(read_in2, 0, MAXSIZE);
}
// fd1可写
if (FD_ISSET(sock->fd1, &writefd))
{
int err2 = 0;
int sendcount2 = 0;
while (totalread2 > 0)
{
int send2 = send(sock->fd1, send_out2 + sendcount2, totalread2, 0);
if (send2 == 0 || (send2 < 0 && errno != EINTR))
{
sprintf(msgbuf, "[%d] Error: 写入fd1出错\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
err2 = 1;
break;
}
if ((send2 < 0) && (errno == ENOSPC)) break;
sendcount2 += send2;
totalread2 -= send2;
sprintf(msgbuf, "[%d] fd1成功在地址: %16s:%d上面发送%d字节\r\n", sock->idx, host1, port1, send2);
outprint(msgbuf, strlen(msgbuf));
}
if (err2 == 1) break;
if ((totalread2 > 0) && (sendcount2 > 0))
{
memcpy(send_out2, send_out2+sendcount2, totalread2);
memset(send_out2 + totalread2, 0, MAXSIZE - totalread2);
}
else
{
memset(send_out2, 0, MAXSIZE);
}
}
}
// 关闭socket
closesocket(sock->fd1);
closesocket(sock->fd2);
sprintf(msgbuf, "[%d] 成功关闭掉两个socket, fd1, fd2\r\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
sprintf(msgbuf, "[%d] 本次数据转发结束\r\n\n", sock->idx);
outprint(msgbuf, strlen(msgbuf));
}