1,nginx-lua
需要设置nginx配置文件
resolver 223.5.5.5 223.6.6.6; lua_package_path "/usr/local/nginx/conf/lua-resty-http/lib/?.lua;/usr/local/nginx/conf/lua-resty-string/lib/?.lua;;"; init_worker_by_lua_file /usr/local/nginx/conf/init.lua;
代码
local sleepTime = 5 local remoteIp = "127.0.0.1" local remotePort = 9527 local function getLocalClient() return "clientOne" , nil end local function encryptMessage(skey, msg) local aes = require "resty.aes" local str = require "resty.string" local aes_128_cbc_with_iv = assert(aes:new(skey, nil, aes.cipher(128,"cbc"), {iv="1234567890123456"})) local encrypted = ngx.encode_base64(aes_128_cbc_with_iv:encrypt(msg)) return encrypted end local function decryptMessage(skey, msg) local aes = require "resty.aes" local str = require "resty.string" local aes_128_cbc_with_iv = assert(aes:new(skey, nil, aes.cipher(128,"cbc"), {iv="1234567890123456"})) local decrypted = aes_128_cbc_with_iv:decrypt(ngx.decode_base64(msg)) return decrypted end local function modifySleeptime() sleepTime = math.random(10) end local function sendMessage(sock, skey, msg, pkgtype) if pkgtype == "hello" then msg = msg else msg = encryptMessage(skey, msg) end local len = string.len(msg) local res={0,0,0,0} local num = len local n = math.ceil(select(2,math.frexp(num))/8) for k=n,1,-1 do local mul=2^(8*(k-1)) res[k]=math.floor(num/mul) num=num-res[k]*mul end sock:send(string.char(res[1]) .. string.char(res[2]) .. string.char(res[3]) .. string.char(res[4]) .. msg) end local function recvMessage(sock, skey) sock:settimeout(6000) local line, err, partial = sock:receive(4) if not line then return nil, err end local len = string.byte(line,1) + string.byte(line,2)*256 + string.byte(line,3)*256*256 + string.byte(line,4)*256*256*256 local msg, err, partial = sock:receive(len) if not msg then return nil, err end msg = decryptMessage(skey, msg) return msg, nil end local function handle(sock, client, skey) local connect = 0 sendMessage(sock, skey, client, "connect") local skey, err = recvMessage(sock, skey) if not skey then ngx.timer.at(sleepTime, loop) modifySleeptime() return end while true do connect = connect + 1 if ngx.worker.exiting() then return "exit" end local msg, err = recvMessage(sock, skey) if not msg then _, pos = string.find(err, "timeout") if pos ~= nil and connect < 60 then sendMessage(sock, skey, "hello", "hello") else sock:close() return "connection error or closed" end else connect = 0 msg = string.gsub(msg, "^%s*(.-)%s*$", "%1") local http = require("resty.http") local httpc = http.new() local res, err = httpc:request_uri("http://www.ciaos.com"..msg, { method = "GET", headers = { ["Content-Type"] = "application/x-www-form-urlencoded", } }) local result if not res then result = err else result = res.body end sendMessage(sock, skey, result, "message") end end end local function loop() local client, err = getLocalClient() if not client then ngx.timer.at(sleepTime, loop) modifySleeptime() return end while true do if ngx.worker.exiting() then break end local sock = ngx.socket.tcp() local ok, err = sock:connect(remoteIp, remotePort) if not ok then ngx.timer.at(sleepTime, loop) modifySleeptime() return else local err = handle(sock, client, "a$ef&_12b(*;32a1") if err then ngx.timer.at(sleepTime, loop) modifySleeptime() break end end end end ngx.timer.at(3, loop)
golang(需要依赖gotcp项目)
代码
// server/server.go package main import ( "encoding/binary" "fmt" "log" "net" "os" "os/signal" "runtime" "syscall" "time" "auth" "gotcp" "proto" ) var clientMap map[uint32]*gotcp.Conn type Callback struct{} func (this *Callback) OnConnect(c *gotcp.Conn) bool { addr := c.GetRawConn().RemoteAddr() c.PutExtraData(addr) fmt.Println("OnConnect["+time.Now().Format("2006-01-02 15:04:05")+"]:", addr) return true } func (this *Callback) OnMessage(c *gotcp.Conn, p gotcp.Packet) bool { rcPacket := p.(*proto.RcPacket) var msgtype string if c.GetFirstPackageFlag() { msgtype = "auth" c.SetFirstPackageFlag() uclientid, skey, err := auth.GetClientId(rcPacket.GetBody()) if err != nil { fmt.Printf("OnMessage["+time.Now().Format("2006-01-02 15:04:05")+"]: %v MsgType[%v] MsgLen[%v] MsgBody[%v] AuthError[%v] ", c.GetRawConn().RemoteAddr(), msgtype, rcPacket.GetLength(), string(rcPacket.GetBody()), err.Error()) c.Close() return false } c.SetClientId(uclientid) clientMap[uclientid] = c bSkey := []byte(skey) c.AsyncWritePacket(proto.NewRcPacket(bSkey, false), time.Second) } else { msgtype = "resp" if rcPacket.GetLength() == 5 && string(rcPacket.GetBody()) == "hello" { fmt.Printf("OnHello["+time.Now().Format("2006-01-02 15:04:05")+"]:%v ClientId[%v] ", c.GetRawConn().RemoteAddr(), c.GetClientId()) return true } c.GetRelateConn().AsyncWritePacket(proto.NewRcPacket(rcPacket.Serialize(), true), time.Second) c.Cmutex.Unlock() } fmt.Printf("OnMessage["+time.Now().Format("2006-01-02 15:04:05")+"]:%v ClientId[%v] MsgType[%v] MsgLen[%v] MsgBody[%v] ", c.GetRawConn().RemoteAddr(), c.GetClientId(), msgtype, rcPacket.GetLength(), string(rcPacket.GetBody())) return true } func (this *Callback) OnClose(c *gotcp.Conn) { fmt.Println("OnClose["+time.Now().Format("2006-01-02 15:04:05")+"]:", c.GetExtraData()) if c.GetRelateConn() != nil { c.GetRelateConn().Close() } delete(clientMap, c.GetClientId()) } type InnerCallback struct{} func (this *InnerCallback) OnConnect(c *gotcp.Conn) bool { addr := c.GetRawConn().RemoteAddr() c.PutExtraData(addr) fmt.Println("Inner OnConnecti["+time.Now().Format("2006-01-02 15:04:05")+"]:", addr) return true } func (this *InnerCallback) OnMessage(c *gotcp.Conn, p gotcp.Packet) bool { rcPacket := p.(*proto.RcPacket) clientid := binary.LittleEndian.Uint32(rcPacket.GetBody()[0:4]) fmt.Printf("OnMessage["+time.Now().Format("2006-01-02 15:04:05")+"]: %v ClientId[%v] MsgType[%v] MsgLen[%v] MsgBody[%v] ", c.GetRawConn().RemoteAddr(), clientid, "req", rcPacket.GetLength(), string(rcPacket.GetBody())) if conn, ok := clientMap[clientid]; ok { conn.Cmutex.Lock() conn.SetRelateConn(c) conn.AsyncWritePacket(proto.NewRcPacket(rcPacket.GetBody()[4:], false), time.Second) } else { c.Close() return false } return true } func (this *InnerCallback) OnClose(c *gotcp.Conn) { fmt.Println("Inner OnClose["+time.Now().Format("2006-01-02 15:04:05")+"]:", c.GetExtraData()) } func outer() *gotcp.Server { // creates a tcp listener tcpAddr, err := net.ResolveTCPAddr("tcp4", ":9527") checkError(err) listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err) // creates a server config := &gotcp.Config{ PacketSendChanLimit: 5, PacketReceiveChanLimit: 5, } srv := gotcp.NewServer(config, &Callback{}, &proto.RcProtocol{}) // starts service go srv.Start(listener, time.Second) fmt.Println("listening:", listener.Addr()) return srv } func inner() *gotcp.Server { // creates a tcp listener tcpAddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:9528") checkError(err) listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err) // creates a server config := &gotcp.Config{ PacketSendChanLimit: 20, PacketReceiveChanLimit: 20, } srv := gotcp.NewServer(config, &InnerCallback{}, &proto.RcProtocol{}) // starts service go srv.Start(listener, time.Second) fmt.Println("listening:", listener.Addr()) return srv } func main() { runtime.GOMAXPROCS(runtime.NumCPU()) clientMap = make(map[uint32]*gotcp.Conn) innerSvr := inner() outerSvr := outer() // catchs system signal chSig := make(chan os.Signal) signal.Notify(chSig, syscall.SIGINT, syscall.SIGTERM) fmt.Println("Signal: ", <-chSig) // stops service innerSvr.Stop() outerSvr.Stop() } func checkError(err error) { if err != nil { log.Fatal(err) } }
// auth/auth.go package auth import ( "fmt" "io/ioutil" "net/http" "strconv" "strings" ) func GetClientId(message []byte) (uint32, string, error) { res, err := http.Post("http://www.ciaos.com/service/token", "application/x-www-form-urlencoded", strings.NewReader("param="+string(message))) if err != nil { return 0, "", err } result, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { return 0, "", err } info := strings.Split(string(result), " ") clientid, err := strconv.Atoi(info[0]) uclientid := uint32(clientid) skey := info[1] return uclientid, skey, nil }
gotcp中conn.go文件修改如下
type Conn struct { srv *Server conn *net.TCPConn // the raw connection extraData interface{} // to save extra data closeOnce sync.Once // close the conn, once, per instance closeFlag int32 // close flag closeChan chan struct{} // close chanel packetSendChan chan Packet // packet send chanel packetReceiveChan chan Packet // packet receive chanel isFirstPackage bool // first packet clientId uint32 // remote client id relateConn *Conn // the relate controll connection Cmutex sync.Mutex // mutex }
php代码如下
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Service extends CI_Controller { private function genToken($clientid) { return "abcdefghijklmnop"; } private function getClientId($client) { return 1002; } //Get Token public function token() { $_KEY = "a$ef&_12b(*;32a1"; $param = $this->input->post("param"); if($param) { $client = openssl_decrypt(base64_decode($param), 'aes-128-cbc', $_KEY, true, '1234567890123456'); $clientid = self::getClientId($client); $token = self::genToken($clientid); $this->redis->select(1); $this->redis->setex($clientid, 1800, $token); $message = base64_encode(openssl_encrypt($token, 'aes-128-cbc', $_KEY, true,'1234567890123456')); echo $clientid." ".$message; } else{ show_404(); } } //Controll Message public function console() { $id = $this->input->get("id"); $command = $this->input->get("cmd"); if(is_null($command) or $command == false or $id === false or is_null($id)){ echo "invalid cmd"; return; } $port = 9528; $ip = "127.0.0.1"; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket < 0) { echo "internal server error:1"; return; } $result = socket_connect($socket, $ip, $port); if (!$result) { echo "internal server error:2"; return; } $this->redis->select(1); $stoken = $this->redis->get($id); if(is_null($stoken)){ echo "internal server error:3"; return; } $message = openssl_encrypt($command,'aes-128-cbc',$stoken, true,'1234567890123456'); $message = base64_encode($message); $len = strlen($message)+4; $bin_head = pack("ii", $len, $id); socket_write($socket, $bin_head, strlen($bin_head)); $in = $message; if(!socket_write($socket, $in, strlen($in))) { echo "internal server error:5"; return; } $out = socket_read($socket, 4); if($out && strlen($out)>0){ $data = unpack("i", $out); $out = socket_read($socket, $data[1]); if($out){ $message = openssl_decrypt(base64_decode($out), 'aes-128-cbc', $stoken, true, '1234567890123456'); echo $message; socket_close($socket); return; } } socket_close($socket); echo "internal server error: 4"; } } /* End of file service.php */ /* Location: ./application/controllers/service.php */