Last active
September 26, 2023 06:26
-
-
Save keyganker/a57d9004c05ad3b32bdcf8922367c951 to your computer and use it in GitHub Desktop.
simple tcp proxy implement for experiment #php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param $lPort 本地端口 | |
* @param $rHost 远程主机 | |
* @param $rPort 远程端口 | |
*/ | |
function actionProxy2($lPort, $rHost, $rPort) | |
{ | |
$recvTimeoutSec = 5; | |
$localServer = stream_socket_server("tcp://0.0.0.0:$lPort", $lErrno, $lErrstr); | |
if ($localServer === FALSE) | |
{ | |
die('TSocket: Could not connect to 0.0.0.0:'.$lPort.' ('.$lErrstr.' ['.$lErrno.'])'); | |
} | |
else | |
{ | |
echo "Local connect succ...\n"; | |
} | |
//stream_set_blocking($rHandle, false); | |
stream_set_blocking($localServer, false); | |
$handles = ['local' => $localServer]; | |
$localToRemoteMap = [];//本地连接和远程连接的mapping | |
$localConns = [];//本地连接 | |
while (true) | |
{ | |
$read = $handles; | |
$readable = @stream_select($read, $_w = NULL, $_e = NULL, 5); | |
if ($readable > 0) | |
{ | |
foreach ($read as $item) | |
{ | |
echo "reading...\n"; | |
$key = array_search($item, $handles); | |
if ($key === 'local') | |
{ | |
echo "Accept new connection\n"; | |
$currentLocalConn = stream_socket_accept($localServer); | |
$rHandle = stream_socket_client("tcp://$rHost:$rPort", $errno, $errstr, $recvTimeoutSec); | |
if ($rHandle === FALSE) | |
{ | |
echo 'TSocket: Could not connect to '.$rHost.':'.$rPort.' ('.$errstr.' ['.$errno.'])' . "\n"; | |
@stream_socket_shutdown($currentLocalConn, STREAM_SHUT_RDWR); | |
continue; | |
} | |
$handles[$currentLocalConn] = $currentLocalConn; | |
$handles[$rHandle] = $rHandle; | |
$localToRemoteMap[$currentLocalConn] = $rHandle; | |
$localConns[$currentLocalConn] = $currentLocalConn; | |
} | |
elseif (isset($localToRemoteMap[$item])) | |
{ | |
$data = @stream_socket_recvfrom($item, 1500); | |
if (strlen($data) == 0) | |
{ | |
closeConn($item, $localToRemoteMap[$item], $localToRemoteMap, $localConns, $handles); | |
} | |
else | |
{ | |
echo "Receive data from local and send to remote: $data\n"; | |
@stream_socket_sendto($localToRemoteMap[$item], $data); | |
//@fwrite($proxyMapping[$item], $data); | |
} | |
} | |
elseif (($localConnId = array_search($item, $localToRemoteMap)) !== false) | |
{ | |
$data = @stream_socket_recvfrom($item, 1500); | |
if (strlen($data) == 0) | |
{ | |
$this->closeConn($localConns[$localConnId], $item, $localToRemoteMap, $localConns, $handles); | |
} | |
else | |
{ | |
echo "Receive data from remote and send to local: $data\n"; | |
//@stream_socket_sendto($index, $data); | |
@fwrite($localConns[$localConnId], $data); | |
} | |
} | |
else | |
{ | |
echo "Error!\n"; | |
@stream_socket_shutdown($item, STREAM_SHUT_RDWR); | |
unset($handles[$item]); | |
} | |
} | |
} | |
else | |
{ | |
echo "No readable\n"; | |
} | |
} | |
} | |
function closeConn($local, $remote, &$localToRemoteMap, &$localConns, &$handles) | |
{ | |
@stream_socket_shutdown($remote, STREAM_SHUT_RDWR);//close remote | |
@stream_socket_shutdown($local, STREAM_SHUT_RDWR);//close mapping local | |
if(isset($localToRemoteMap[$local])) unset($localToRemoteMap[$local]);//remove local to remote mapping | |
if(isset($localConns[$local])) unset($localConns[$local]);//remove local from local conns | |
if(isset($handles[$remote])) unset($handles[$remote]);//remove remote from event loop | |
if(isset($handles[$local])) unset($handles[$local]);//remove local from event loop | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment