数据包发送但收不到数据包

Posted

技术标签:

【中文标题】数据包发送但收不到数据包【英文标题】:Packet Sent but cannot Received Packets 【发布时间】:2015-11-17 08:23:35 【问题描述】:

我一直在为 *** 编辑 androids toy*** 示例项目,我为我的示例应用程序得到了这个

我知道我的代码有问题/缺失,因为当我通过 android 设置手动设置 *** 时,有数据包接收,这就是原因 我一直在寻找如何接收数据包,但我不知道如何让它工作。

这是我的源代码,扩展了 ***Service 的 VCL

import android.app.PendingIntent;
import android.net.***Service;
import android.os.ParcelFileDescriptor;
import android.util.Log;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

/**
 * Created by Jameshwart Lopez on 8/18/15.
 */
public class VCL extends ***Service 

    private static final String TAG = "***ClientLibrary";
    private Thread mThread;
    private ParcelFileDescriptor mInterface;

    private String mServerAddress;
    private String mServerPort;
    private PendingIntent mConfigureIntent;
    private String mParameters;

    //a. Configure a builder for the interface.
    Builder builder = new Builder();

    public  void vclRun()
        try 
            //a. Configure the TUN and get the interface.
            mInterface = builder.setSession("thesessionname")
                    .addAddress("192.168.0.1",24)
                    .addDnsServer("8.8.8.8")
                    .addRoute("0.0.0.0", 0).establish();
            //b. Packets to be sent are queued in this input stream.
            FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());

            //b. Packets received need to be written to this output stream.
            FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());

            // Allocate the buffer for a single packet.
            ByteBuffer packet = ByteBuffer.allocate(32767);

            //c. The UDP channel can be used to pass/get ip package to/from server
            DatagramChannel tunnel = DatagramChannel.open();

            // Connect to the server, localhost is used for demonstration only.
            mServerAddress="";//some of the *** ip address here
            mServerPort="1723";
            InetSocketAddress server = new InetSocketAddress(mServerAddress, Integer.parseInt(mServerPort) );
            tunnel.connect(server);

            // For simplicity, we use the same thread for both reading and
            // writing. Here we put the tunnel into non-blocking mode.
            tunnel.configureBlocking(false);


            // Authenticate and configure the virtual network interface.
            handshake(tunnel);

            //d. Protect this socket, so package send by it will not be feedback to the *** service.
            protect(tunnel.socket());

            int timer = 0;
            //e. Use a loop to pass packets.
            while (true) 
                //get packet with in
                //put packet to tunnel
                //get packet form tunnel
                //return packet with out
                //sleep is a must

                // Assume that we did not make any progress in this iteration.
                boolean idle = true;

                // Read the outgoing packet from the input stream.
                int length = in.read(packet.array());
                if (length > 0) 
                    // Write the outgoing packet to the tunnel.
                    packet.limit(length);
                    tunnel.write(packet);
                    packet.clear();

                    // There might be more outgoing packets.
                    idle = false;

                    // If we were receiving, switch to sending.
                    if (timer < 1) 
                        timer = 1;
                    
                

                // Read the incoming packet from the tunnel.
                length = tunnel.read(packet);
                if (length > 0) 
                    // Ignore control messages, which start with zero.
                    if (packet.get(0) != 0) 
                        // Write the incoming packet to the output stream.
                        out.write(packet.array(), 0, length);
                    
                    packet.clear();

                    // There might be more incoming packets.
                    idle = false;

                    // If we were sending, switch to receiving.
                    if (timer > 0) 
                        timer = 0;
                    
                

                // If we are idle or waiting for the network, sleep for a
                // fraction of time to avoid busy looping.
                if (idle) 
                    Thread.sleep(100);

                    // Increase the timer. This is inaccurate but good enough,
                    // since everything is operated in non-blocking mode.
                    timer += (timer > 0) ? 100 : -100;

                    // We are receiving for a long time but not sending.
                    if (timer < -15000) 
                        // Send empty control messages.
                        packet.put((byte) 0).limit(1);
                        for (int i = 0; i < 3; ++i) 
                            packet.position(0);
                            tunnel.write(packet);
                        
                        packet.clear();

                        // Switch to sending.
                        timer = 1;
                    

                    // We are sending for a long time but not receiving.
                    //if (timer > 20000) 
                    //    throw new IllegalStateException("Timed out");
                    //
                


            
         catch (Exception e) 
            // Catch any exception
            e.printStackTrace();
         finally 
            try 
                if (mInterface != null) 
                    mInterface.close();
                    mInterface = null;
                
             catch (Exception e) 
            
        
    

    private void handshake(DatagramChannel tunnel) throws Exception 
        // To build a secured tunnel, we should perform mutual authentication
        // and exchange session keys for encryption. To keep things simple in
        // this demo, we just send the shared secret in plaintext and wait
        // for the server to send the parameters.
        // Allocate the buffer for handshaking.
        ByteBuffer packet = ByteBuffer.allocate(1024);

        // Control messages always start with zero.
        String password = "";//*** password here
        packet.put((byte) 0).put(password.getBytes()).flip();

        // Send the secret several times in case of packet loss.
        for (int i = 0; i < 3; ++i) 
            Log.e("packetsdata", packet.toString());
            packet.position(0);
            tunnel.write(packet);
        
        packet.clear();

        // Wait for the parameters within a limited time.
        for (int i = 0; i < 50; ++i) 
            Thread.sleep(100);

            // Normally we should not receive random packets.
            int length = tunnel.read(packet);
            if (length > 0 && packet.get(0) == 0) 
                configure(new String(packet.array(), 1, length - 1).trim());
                return;
            
        
        //throw new IllegalStateException("Timed out");
    
    private void configure(String parameters) throws Exception 
        // If the old interface has exactly the same parameters, use it!
        if (mInterface != null) 
            Log.i(TAG, "Using the previous interface");
            return;
        

        // Configure a builder while parsing the parameters.
        Builder builder = new Builder();
        for (String parameter : parameters.split(" ")) 
            String[] fields = parameter.split(",");
            try 
                switch (fields[0].charAt(0)) 
                    case 'm':
                        builder.setMtu(Short.parseShort(fields[1]));
                        break;
                    case 'a':
                        builder.addAddress(fields[1], Integer.parseInt(fields[2]));
                        break;
                    case 'r':
                        builder.addRoute(fields[1], Integer.parseInt(fields[2]));
                        break;
                    case 'd':
                        builder.addDnsServer(fields[1]);
                        break;
                    case 's':
                        builder.addSearchDomain(fields[1]);
                        break;
                
             catch (Exception e) 
                throw new IllegalArgumentException("Bad parameter: " + parameter);
            
        

        // Close the old interface since the parameters have been changed.
        try 
            mInterface.close();
         catch (Exception e) 
            // ignore
        

        // Create a new interface using the builder and save the parameters.
        mInterface = builder.setSession(mServerAddress)
                .setConfigureIntent(mConfigureIntent)
                .establish();
        mParameters = parameters;
        Log.i(TAG, "New interface: " + parameters);
    

这就是我使用上面的类的方式

private Thread mThread;

    /*
    * Services interface
    * */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        // Start a new session by creating a new thread.
        mThread = new Thread(this, "***Runnable");
        //start the service
        mThread.start();
        /*
         *service is left "started" and will later be restarted by the system
         * http://android-developers.blogspot.com.au/2010/02/service-api-changes-starting-with.html
         */
        return START_STICKY;
    
    @Override
    public void onDestroy() 

        if (mThread != null) 
            mThread.interrupt();
        
        super.onDestroy();
    


    @Override
    public synchronized void run() 
        /*
        * to run the *** interface call the vclRun method inside VCL class
        * */
       this.vclRun();
    

【问题讨论】:

我在 toy*** 示例中得到了它。 我的想法是,当我将数据包写入隧道时完成 我写了哪一部分来发送而不是接收?你能在我的代码中指出它吗?这可能对我有帮助。 :) 【参考方案1】:

首先,检查是否有字节发送到您的 Android 设备。因为如果没有要接收的内容,它将不会读取任何内容。

然后看看这个,因为它可能会破坏您的连接。

您需要在onStartCommand 中包含此内容:

// The handler is only used to show messages.
if (mHandler == null) 
    mHandler = new Handler(this);

// Stop the previous session by interrupting the thread.
if (mThread != null) 
    mThread.interrupt();

// Extract information from the intent.
String prefix = getPackageName();
mServerAddress = intent.getStringExtra(prefix + ".ADDRESS");
mServerPort = intent.getStringExtra(prefix + ".PORT");
mSharedSecret = intent.getStringExtra(prefix + ".SECRET").getBytes();
// Start a new session by creating a new thread.
mThread = new Thread(this, "Toy***Thread");
mThread.start();
return START_STICKY;

还有sychronized void 的详细信息(如下所示)。

@Override
public synchronized void run() 
    try 
        Log.i(TAG, "Starting");


        // If anything needs to be obtained using the network, get it now.
        // This greatly reduces the complexity of seamless handover, which
        // tries to recreate the tunnel without shutting down everything.
        // In this demo, all we need to know is the server address.


        InetSocketAddress server = new InetSocketAddress(
                mServerAddress, Integer.parseInt(mServerPort));
        // We try to create the tunnel for several times. The better way
        // is to work with ConnectivityManager, such as trying only when
        // the network is avaiable. Here we just use a counter to keep
        // things simple.
        for (int attempt = 0; attempt < 10; ++attempt) 
            mHandler.sendEmptyMessage(R.string.connecting);
            // Reset the counter if we were connected.

            // See BELOW 
            if (run(server))  
                attempt = 0;
            

            // Sleep for a while. This also checks if we got interrupted.
            Thread.sleep(3000);
         /..../

您没有很好地管理线程操作。建议在尝试运行之前接收任何需要接收的字节。不这样做会导致问题。 我会回顾你的代码并把你拿出来的东西放进去。 我还建议您在此处更改代码:

packet.put((byte) 0).put(password.getBytes()).flip();

尝试使用显式编码:

packet.put((byte) 0).put(password.getBytes("UTF-8")).flip();

因为没有它,数据可能会丢失。看到这个答案:https://***.com/a/7947911/3956566

我已检查,您的项目使用的是“UTF-8”。

如果这没有帮助,请告诉我。

【讨论】:

如何接收数据包?我不明白 我尝试为 *** 复制谷歌示例,它甚至发送了数据包,这就是我尝试编辑它的原因 我的意思是它甚至不发送数据包,我会遇到 PortUnreachableException 和 SocketException 现在我已经得到了 PortUnreachableException。我认为这是在 *** 服务器端无法访问的端口。

以上是关于数据包发送但收不到数据包的主要内容,如果未能解决你的问题,请参考以下文章

网络连接数据包经常发送不了

如果启用了环回,为啥发送方收不到它的多播 UDP 数据包?

网卡收发数据包数量大的惊人如何解决

网卡只发送,不接收的问题

邀请侦听器无法正常工作 4.1

如何在 Qt 中读取下一个数据包