吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 913|回复: 19
收起左侧

[求助] [java] 在做socket5 proxy时遇见一个问题,只要是新来的连接转发后立马会关闭

  [复制链接]
Dream_Peng 发表于 2022-11-21 10:02
本帖最后由 Dream_Peng 于 2022-11-21 10:15 编辑

我是在proxy一个游戏的时候发生的这个问题,问题描述如下:
先要解释:
1.首先游戏登录 使用端口是127.0.0.1:20000
2.登录成功跳转到角色选择  使用端口是127.0.0.1:20002

我proxy的是该游戏的20000-30000端口,所有地址

步骤如下:
1.在客户端输入账号密码,连接127.0.0.1:20000 进行账号验证
2.登录成功进入角色选择,  断开127.0.0.1:20000 连接  转向127.0.0.1:20002进行连接
3.没然后了,连接127.0.0.1:20002 秒断开。


附上代码部分:
[Java] 纯文本查看 复制代码
    public static void main(String[] args) throws IOException {
        /**
         * [url=home.php?mod=space&uid=952169]@Param[/url] args
         */
            ServerSocket serverSocket = new ServerSocket(2233);
            while (true) {
                Socket socket;
                try {
                    socket = serverSocket.accept();
                    new SocketThread(socket).start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    }


下面是SocketThread:
[Java] 纯文本查看 复制代码
 private Socket socketIn;
    private InputStream isIn;
    private OutputStream osIn;
    //
    private Socket socketOut;
    private InputStream isOut;
    private OutputStream osOut;

    public SocketThread(Socket socket) {
        this.socketIn = socket;
    }

    private byte[] buffer = new byte[4096];
    private static final byte[] VER = {0x5, 0x0};
    private static final byte[] CONNECT_OK = {0x5, 0x0, 0x0, 0x1, 0x7F, 0x0, 0x0, 0x1, 0x0, 0x0};

    public void run() {
        String host = "";
        int port = 0;
        try {
            System.out.println(" a client connect " + socketIn.getInetAddress() + ":" + socketIn.getPort());
            isIn = socketIn.getInputStream();
            osIn = socketIn.getOutputStream();
            //获取客户端请求认证数据(版本(长度1)、认证方式数量(长度1)、认证方式(长度1-255))
            int len = isIn.read(buffer);
            //System.out.println("< " + bytesToHexString(buffer, 0, len));
            //此处返回客户端认证方式(版本(长度1)、认证方式(长度1))
            osIn.write(VER);
            osIn.flush();
            //System.out.println("> " + bytesToHexString(VER, 0, VER.length));
            //授权通过,客户端请求建立连接(版本(长度1)、请求类型(长度1)、保留字节(长度1)(默认00)、(长度1)客户端地址类型、客户端地址、客户端端口(长度2))
            len = isIn.read(buffer);
            //System.out.println("< " + bytesToHexString(buffer, 0, len));
            // 查找主机和端口
            byte cmd = buffer[1];
            if (cmd == 1) {
                host = findHost(buffer, 4, len - 3);
                port = findPort(buffer, len);
                System.out.println("link to remote : " + host + ":" + port);
                //连接原主机需要连接的地址
                socketOut = new Socket(host, port);
                isOut = socketOut.getInputStream();
                osOut = socketOut.getOutputStream();
                //告知客户端已连接成功,并返回
                System.out.println(buffer[2]);
                byte[] b = HexStrToByteArray("05 00 00 01 7F 00 00 01 " + Integer.toHexString(socketOut.getLocalPort()).toUpperCase());
                System.out.println("代{过}{滤}理返回本地数据: " + bytesToHexString(b, 0, b.length));
                osIn.write(b);
                osIn.flush();

                //System.out.println("[client] : " + bytesToHexString(CONNECT_OK, 0, CONNECT_OK.length));
                //将客户端请求内容转发给真实目标端
                SocketThreadOutput out = new SocketThreadOutput(isIn, osOut);
                out.start();
                //将真实目标端响应内容转发给客户端
                SocketThreadInput in = new SocketThreadInput(isOut, osIn);
                in.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("the proxy socket can't connect, " + host + ":" + port);
            System.out.println("a client leave");
        } finally {
            try {
                if (socketIn != null) {
                    socketIn.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static String findHost(byte[] bArray, int begin, int end) {
        //将IP地址转10进制  仅支持IPV4
        StringBuilder sb = new StringBuilder();
        for (int i = begin; i <= end; i++) {
            sb.append(0xFF & bArray[i]);
            sb.append(".");
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }

    public static int findPort(byte[] bArray, int len) {
        //将最后两位端口号如:4E 20 转换成十进制  20000
        return ByteBuffer.wrap(bArray, len - 2, 2).asShortBuffer().get() & 0xFFFF;
    }

    /**
     * 字节数组转16进制文本
     *
     * @param bArray 字节数组
     * @param begin  开始位置
     * @param end    结束位置
     * [url=home.php?mod=space&uid=155549]@Return[/url] 16进制文本
     */
    public static String bytesToHexString(byte[] bArray, int begin, int end) {
        StringBuilder sb = new StringBuilder(bArray.length);
        String sTemp;
        for (int i = begin; i < end; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
            sb.append(" ");
        }
        return sb.toString();
    }


里面两个方法
[Java] 纯文本查看 复制代码
    private InputStream isIn;
    private OutputStream osOut;

    public SocketThreadOutput(InputStream isIn, OutputStream osOut) {
        this.isIn = isIn;
        this.osOut = osOut;
    }

    private byte[] buffer = new byte[4096];

    public void run() {
        try {
            int len;
            while ( (len = isIn.read(buffer))!=-1) {
                if (len > 0) {
                    osOut.write(buffer, 0, len);
                    osOut.flush();
                    System.out.println("客户端请求: " + bytesToHexString(buffer, 0, len));

                }
            }
        } catch (Exception e) {
            System.out.println("SocketThreadOutput leave");
        }
    }


[Java] 纯文本查看 复制代码
   private InputStream isOut;
    private OutputStream osIn;

    public SocketThreadInput(InputStream isOut, OutputStream osIn) {
        this.isOut = isOut;
        this.osIn = osIn;
    }

    private byte[] buffer = new byte[4096];

    public void run() {
        try {
            int len;
            while ( (len = isOut.read(buffer))!=-1) {
                if (len > 0) {
                    osIn.write(buffer, 0, len);
                    osIn.flush();
                    System.out.println("服务端返回: " + bytesToHexString(buffer, 0, len));
                }
            }
        } catch (Exception e) {
            System.out.println("SocketThreadInput leave");
        }
    }


求教为什么会断开呢?

附上源码,后缀改java即可
Main.java
Main.txt (628 Bytes, 下载次数: 1)
SocketThread.java
SocketThread.txt (4.91 KB, 下载次数: 1)
SocketThreadInput.java
SocketThreadInput.txt (972 Bytes, 下载次数: 1)
SocketThreadOutput.java
SocketThreadOutput.txt (1002 Bytes, 下载次数: 1)



免费评分

参与人数 2吾爱币 +1 热心值 +2 收起 理由
Malevolence52 + 1 + 1 热心回复!
CYLmtthhh + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Broadm 发表于 2022-11-21 10:53
finally {
           try {
               if (socketIn != null) {
                   socketIn.close();
               }
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
开启2个线程后,代码不就执行到这里了? 然后就关闭了客户端的socket
 楼主| Dream_Peng 发表于 2022-11-21 10:57
Broadm 发表于 2022-11-21 10:53
finally {
           try {
               if (socketIn != null) {

这不是finally么  就算把当前的关闭了 也不应该关闭  new SocketThread(socket).start(); 出来的连接吧?
Broadm 发表于 2022-11-21 11:08
               //System.out.println("[client] : " + bytesToHexString(CONNECT_OK, 0, CONNECT_OK.length));
               //将客户端请求内容转发给真实目标端
               SocketThreadOutput out = new SocketThreadOutput(isIn, osOut);
               out.start();
               //将真实目标端响应内容转发给客户端
               SocketThreadInput in = new SocketThreadInput(isOut, osIn);
               in.start();


执行完这2个代码,直接就进去finally了啊, 然后线程就退出了,你的代{过}{滤}理的新开的socket都是这个线程里面的局部变量,肯定就销毁了啊
Broadm 发表于 2022-11-21 11:15
Broadm 发表于 2022-11-21 11:08
//System.out.println("[client] : " + bytesToHexString(CONNECT_OK, 0, CONNECT_OK.lengt ...

你在main里面开了个线程1, 这个线程1里面又开了2个线程,   代{过}{滤}理的socket都在线程1里面,
线程1开了2个新线程然后就没有代码了,直接就运行结束了,不就销毁了吗? 里面的代{过}{滤}理socket都没了
Broadm 发表于 2022-11-21 11:19
           len = isIn.read(buffer);
           //System.out.println("< " + bytesToHexString(buffer, 0, len));
           // 查找主机和端口
           byte cmd = buffer[1];
           if (cmd == 1) {


这里应该改成死循环接受客户端的数据,

然后判断cmd是啥类型,比如是1,需要开启新的代{过}{滤}理连接的话,就new socket
否则就直接转发
代码大概这样

while(true){

    len = isIn.read(buffer);
    //System.out.println("< " + bytesToHexString(buffer, 0, len));
    // 查找主机和端口
    byte cmd = buffer[1];
    if (cmd == 1) {
        //奖励代{过}{滤}理连接
    }else{
        //转发
    }

}
 楼主| Dream_Peng 发表于 2022-11-21 11:20
Broadm 发表于 2022-11-21 11:15
你在main里面开了个线程1, 这个线程1里面又开了2个线程,   代{过}{滤}理的socket都在线程1里面,
线程1 ...

新来的第二个连接也就是 20002端口被proxy进来是走的 main方法 accept 进来的,相当于是一个新对象了, 但是这20002端口poxy的直接就断开了
 楼主| Dream_Peng 发表于 2022-11-21 11:21
Broadm 发表于 2022-11-21 11:15
你在main里面开了个线程1, 这个线程1里面又开了2个线程,   代{过}{滤}理的socket都在线程1里面,
线程1 ...

线程1新开的两个线程被断开是很正常的   只需要加一个join 就可以等待 2个线程完成后再去断开线程1   但是现在问题是 有一个新的poxy线程在mian 中创建  但是这个新创建的被秒关了
Broadm 发表于 2022-11-21 11:22
Dream_Peng 发表于 2022-11-21 11:20
新来的第二个连接也就是 20002端口被proxy进来是走的 main方法 accept 进来的,相当于是一个新对象了, 但 ...

新对象不得处理后续命令么,还是要死循环接受,不能让线程退出
 楼主| Dream_Peng 发表于 2022-11-21 11:23
Broadm 发表于 2022-11-21 11:22
新对象不得处理后续命令么,还是要死循环接受,不能让线程退出

是的这个我也试过 这是我特地删掉来测试的,忘了恢复回来 在SocketThread.java  第 57行之后加入
[Java] 纯文本查看 复制代码
                in.join();
                out.join();

他就会等待两个子线程完成后才继续执行
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表