Miko Android自学之路 WifiDirect中文最强详解,如何传输数据,如何设置GroupOwener,如何设置客户端以及服务器端

10 篇文章 0 订阅
7 篇文章 0 订阅

大家好我是Miko,最近有参加一个比赛,用到了WifiDirect技术,于是翻看官方文档之后,想写一个Demo,Google API Sample已经很老了,还是用的Eclipse,宝宝心好累=_=+///,在CSDN上找了几篇文章,竟然都是些API的国语翻译,程序猿节操何在?这里我将会用自己根据官方Demo重写的Demo来详解WifiDirect的使用。
Android4.0之后开始支持WifiDirect技术,即Wifi直连,做为一种通讯方式,它的优势在于传输速度快传输距离远。
ok
首先上我的DemoGithub地址https://github.com/MikoGodZd/WifiDerect
在上官方文档http://developer.android.com/intl/zh-tw/guide/topics/connectivity/wifip2p.html
官方Demo http://download.csdn.net/detail/yichigo/5516627

通过Wi-Fi Direct查找附近的设备,并与之连接一般包括如下几个骤:
一 设置应用程序权限
二 创建一个广播接收器和对等网络管理器
三 初始化对等点的搜索
四 获取对等点列表
五 连接一个对等点

一、设置权限
我们mainifest中添加如下权限

 <uses-sdk android:minSdkVersion="14" />

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

注:
android.permission.ACCESS_WIFI_STATE 允许程序访问Wi-Fi网络状态信息(Allows applications to access information about Wi-Fi networks)
android.permission.CHANGE_WIFI_STATE 允许程序改变Wi-Fi连接状态(Allows applications to change Wi-Fi connectivity state)
android.permission.INTERNET 当需要访问网络的时候,需要在AndroidManifest.xml里面添加访问网络的权限

二、创建广播接收器
首先在MainActivity中初始化IntentFilter并让它监听以下动作:
WIFI_P2P_STATE_CHANGED_ACTION
* 表明Wi-Fi对等网络(P2P)是否已经启用
WIFI_P2P_PEERS_CHANGED_ACTION
* 表明可用的对等点的列表发生了改变
WIFI_P2P_CONNECTION_CHANGED_ACTION
* 表示Wi-Fi对等网络的连接状态发生了改变
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
* 表示该设备的配置信息发生了改变

 private void initIntentFilter() {
        mFilter = new IntentFilter();
        mFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        mFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        mFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        mFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
        mFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
    }

然后我们创建一个新的广播类

public class WifiDirectBroadcastReceiver extends BroadcastReceiver {

    private WifiP2pManager mManager;
    private WifiP2pManager.Channel mChannel;
    private Activity mActivity;
    private WifiP2pManager.PeerListListener mPeerListListener;
    private WifiP2pManager.ConnectionInfoListener mInfoListener;

    public WifiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, Activity activity,
                                       WifiP2pManager.PeerListListener peerListListener,
                                       WifiP2pManager.ConnectionInfoListener infoListener
    ) {
        this.mManager = manager;
        this.mChannel = channel;
        this.mPeerListListener = peerListListener;
        this.mActivity = activity;
        this.mInfoListener = infoListener;
    }


    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();

        /*check if the wifi is enable*/
        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
             if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {  
                activity.setIsWifiP2pEnabled(true);  
            } else {  
                activity.setIsWifiP2pEnabled(false);  
            }  
        }
        /*get the list*/
        else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

            mManager.requestPeers(mChannel, mPeerListListener);
        }
        /*查看当前是否处于查找状态
        * get the state of discover*/
        else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {

            int State = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, -1);

            if (State == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED)
                Toast.makeText(mActivity, "搜索开启", Toast.LENGTH_SHORT).show();
            else if (State == WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED)
                Toast.makeText(mActivity, "搜索已关闭", Toast.LENGTH_SHORT).show();

        }
        /*Respond to new connection or disconnections
        *查看是否创建连接*/
        else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {

            if (mManager == null) {
                return;
            }

            NetworkInfo networkInfo = (NetworkInfo) intent
                    .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);

            if (networkInfo.isConnected()) {
                Log.i("xyz", "已连接");
                mManager.requestConnectionInfo(mChannel, mInfoListener);
            } else {
                Log.i("xyz", "断开连接");
                return;
            }
        }

        /*Respond to this device's wifi state changing*/
        else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
        }
    }
}

构造函数中的manager以及channel比较好理解,剩下的主要是在mainActivity中的方法的实现
第一个action用于检测当前设备的wifi是否打开很好理解
第二个action当你开始搜索之后,当设备列表发生变化的时候即触发通过mManager.requestPeers(mChannel, mPeerListListener);方法可以的到列表,这些我们下文详讲
第三个action用于检测当前是否处于搜索状态,
第四个action用于检测两个设备连接状态是否改变
第五个action适用于设备名称发生改变这里我们不讲

三、创建搜索,获得列表
ok 广播搭建好之后,我们就要初始化一个p2p了

首先在MainActivity中创建一个Manager以及一个Channel


private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
mManager = (WifiP2pManager) getSystemService(WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, Looper.myLooper(), null);

这样我们就开启了direct服务
下面我们定义搜索函数

   private void DiscoverPeers() {
        mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
            }

            @Override
            public void onFailure(int reason) {
            }
        });
    }

这里面的success以及failure没有任何实质的信息,只是提醒你调用这个方法是否成功,而不代表开启搜索是否成功,要监听搜索的状态,如上文所述我们要在广播中实现

else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {

            int State = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, -1);

            if (State == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED)
                Toast.makeText(mActivity, "搜索开启", Toast.LENGTH_SHORT).show();
            else if (State == WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED)
                Toast.makeText(mActivity, "搜索已关闭", Toast.LENGTH_SHORT).show();

        }

ok开启搜索服务之后,当找到一个设备后,设备列表就会发生改变,这个时候就会触发广播中的第二个action

else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

            mManager.requestPeers(mChannel, mPeerListListener);
        }

通过requestPeers(mChannel, mPeerListListener)再通过监听器中的onPeersAvailable方法就可以得到设备列表,当让我们想在主界面中显示列表,因此监听器我们在activity中实现然后通过传参的方式传入到广播之中,

 WifiP2pManager.PeerListListener mPeerListListerner = new WifiP2pManager.PeerListListener() {
            @Override
            public void onPeersAvailable(WifiP2pDeviceList peersList) {
                peers.clear();
                peersshow.clear();
                Collection<WifiP2pDevice> aList = peersList.getDeviceList();
                peers.addAll(aList);

                for (int i = 0; i < aList.size(); i++) {
                    WifiP2pDevice a = (WifiP2pDevice) peers.get(i);
                    HashMap<String, String> map = new HashMap<String, String>();
                    map.put("name", a.deviceName);
                    map.put("address", a.deviceAddress);
                    peersshow.add(map);
                }
                mAdapter = new MyAdapter(peersshow);
                mRecyclerView.setAdapter(mAdapter);
                mRecyclerView.setLayoutManager(new LinearLayoutManager
                        (MainActivity.this));
                mAdapter.SetOnItemClickListener(new MyAdapter.OnItemClickListener() {
                    @Override
                    public void OnItemClick(View view, int position) {
                        CreateConnect(peersshow.get(position).get("address"),
                                peersshow.get(position).get("name"));

                    }

                    @Override
                    public void OnItemLongClick(View view, int position) {

                    }
                });
            }
        };

这是在Activity中的实现,得到List的方法有很多,我使用了RecyclerView感觉游侠笨重,一定有其他好的方法=_=///
单击每一个设备我所写的Adapter就会返回出来它的MAC地址,通过地址我们就可以来连接设备了
三、创建连接

创建连接我们调用manager中的connect方法,如果连接之前没有创建一个组,系统会自动创建一个组,并且随机分配谁是GroupOwner即谁是组长,这也关系到谁是客户端谁是服务器,
connect方法官方文档解释
If the current device is part of an existing p2p group or has created
* a p2p group with {@link #createGroup}, an invitation to join the group is sent to
* the peer device.

我们写一个方法来创建Group,在两个设备中谁调用这个方法,谁就是组长这样就实现了设定谁是服务器与客户端

 private void BeGroupOwener() {
        mManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {

            }

            @Override
            public void onFailure(int reason) {

            }
        });
    }
 private void CreateConnect(String address, final String name) {
        WifiP2pDevice device;
        WifiP2pConfig config = new WifiP2pConfig();
        Log.i("xyz", address);

        config.deviceAddress = address;
        /*mac地址*/

        config.wps.setup = WpsInfo.PBC;
        Log.i("address", "MAC IS " + address);
        if (address.equals("9a:ff:d0:23:85:97")) {
            config.groupOwnerIntent = 0;
            Log.i("address", "lingyige shisun");
        }
        if (address.equals("36:80:b3:e8:69:a6")) {
            config.groupOwnerIntent = 15;
            Log.i("address", "lingyigeshiwo");

        }

        Log.i("address", "lingyige youxianji" + String.valueOf(config.groupOwnerIntent));

        mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {

            @Override
            public void onSuccess() {

            }

            @Override
            public void onFailure(int reason) {


            }
        });
    }

Wifip2pconfi这个类官方解释是
A class representing a Wi-Fi P2p configuration for setting up a connection
有道翻译 一个类代表一个wi - fi P2p配置为建立一个连接=_=+///
其实是一个类用来储存p2p设备的信息,我们把其中的Address值改为想要链接设备的Mac地址就可以得到设备的实例,

 mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {

            @Override
            public void onSuccess() {

            }

            @Override
            public void onFailure(int reason) {


            }
        });

调用connect方法,实现连接,如上文所述,这里的sucess,以及failure都是表示函数的成功与否,要看是否连接还要到广播之中

 else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {

            if (mManager == null) {
                return;
            }

            NetworkInfo networkInfo = (NetworkInfo) intent
                    .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);

            if (networkInfo.isConnected()) {
                Log.i("xyz", "已连接");
                mManager.requestConnectionInfo(mChannel, mInfoListener);
            } else {
                Log.i("xyz", "断开连接");
                return;
            }
        }

NetWorkInfo方法Describes the status of a network interface. 用来描述网络接口的状态
当网络连接时我们调用此方法mManager.requestConnectionInfo(mChannel, mInfoListener);就可让服务器端开始接受数据了,这里在下文中也会详讲。

四、传输数据前的准备
上文讲到mManager.requestConnectionInfo(mChannel, mInfoListener);方法
第二个参数是ConnectionInfoListener类
Interface for callback invocation when connection info is available用来当connect成功后回掉,跟上一个得List的监听器一样,我们也在MainActivity中实现,然后通过传参到广播之中

        WifiP2pManager.ConnectionInfoListener mInfoListener = new WifiP2pManager.ConnectionInfoListener() {

            @Override
            public void onConnectionInfoAvailable(final WifiP2pInfo minfo) {

                Log.i("xyz", "InfoAvailable is on");
                info = minfo;
                TextView view = (TextView) findViewById(R.id.tv_main);
                if (info.groupFormed && info.isGroupOwner) {
                    Log.i("xyz", "owmer start");

                    mServerTask = new FileServerAsyncTask(MainActivity.this, view);
                    mServerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

                    mDataTask = new DataServerAsyncTask(MainActivity.this, view);
                    mDataTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

                } else if (info.groupFormed) {
                    SetButtonVisible();
                }
            }
        };

我们看一下下面这核心代码

 if (info.groupFormed && info.isGroupOwner) {
                    Log.i("xyz", "owmer start");

                    mServerTask = new FileServerAsyncTask(MainActivity.this, view);
                    mServerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

                    mDataTask = new DataServerAsyncTask(MainActivity.this, view);
                    mDataTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

                } 
                else if (info.groupFormed) {
                    SetButtonVisible();
                }

我们使用的传输方式是UDP模型在这个Demo中只能从客户端向服务器端发送消息
ok知道这个前提之后我们看
第一个判断:如果组已经建立,并且是组长,也就是说当前设备是服务器,我们开启两个AsyncTask分别用来接收图片以及字符串,当然看完这篇博客之后你可以传输各种类型的数据,这里仅以这两个举例
AsyncTask怎么写我们后面再说,
看第二个判断:如果组建立了,但不是组长,也就是说当前设备是客户端,这个时候我们让两个发送Button可见,也就是说一开始所有的设备界面都是一样的没有发送数据的按钮,但判断出谁是客户端之后,我们就将发送按钮展现出来。
上截图
客户端界面
服务器端界面
ok搜索连接都讲完了,下面就是大头传送数据了
五、传输数据
1.客户端 发送服务的编写
Activity中设置发送图片按钮的监听器

 sendpicture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.setType("image/*");
                startActivityForResult(intent, 20);

            }
        });

Intent intent = new Intent(Intent.ACTION_GET_CONTENT)
官方文档Allow the user to select a particular kind of data and return it.
这个Intent会打开文件管理器
intent.setType(“image/*”);这个语句决定着以什么方式打开,我们设以图片方式打开,启动Activity后我们选择好图片,之后Activity关闭自动调用onActivityResult

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 20) {
            super.onActivityResult(requestCode, resultCode, data);
            Uri uri = data.getData();
            Intent serviceIntent = new Intent(MainActivity.this,
                    FileTransferService.class);

            serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
            serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH,
                    uri.toString());

            serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
                    info.groupOwnerAddress.getHostAddress());
            serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT,
                    8988);
            MainActivity.this.startService(serviceIntent);
        }
    }

Uri uri = data.getData();获得图片所在位置
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH,uri.toString());将位置传入Service
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,info.groupOwnerAddress.getHostAddress());传入组长的IP地址,用来创建Socket端口
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT,8988);传入端口port
ok下面我们看服务究竟怎么写

public class FileTransferService extends IntentService {

    private static final int SOCKET_TIMEOUT = 5000;
    public static final String ACTION_SEND_FILE = "com.example.android.wifidirect.SEND_FILE";
    public static final String EXTRAS_FILE_PATH = "sf_file_url";
    public static final String EXTRAS_GROUP_OWNER_ADDRESS = "sf_go_host";
    public static final String EXTRAS_GROUP_OWNER_PORT = "sf_go_port";

    public FileTransferService(String name) {
        super(name);
    }

    public FileTransferService() {
        super("FileTransferService");
    }

    /*
     * (non-Javadoc)
     *
     * @see android.app.IntentService#onHandleIntent(android.content.Intent)
     */
    @Override
    protected void onHandleIntent(Intent intent) {

        Context context = getApplicationContext();
        if (intent.getAction().equals(ACTION_SEND_FILE)) {
            String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);

            String host = intent.getExtras().getString(
                    EXTRAS_GROUP_OWNER_ADDRESS);

            Socket socket = new Socket();

            int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);

            try {
                Log.d("xyz", "Opening client socket - ");
                socket.bind(null);
                socket.connect((new InetSocketAddress(host, port)),
                        SOCKET_TIMEOUT);

                Log.d("xyz",
                        "Client socket - " + socket.isConnected());

                /*returns an output stream to write data into this socket*/
                OutputStream stream = socket.getOutputStream();
                ContentResolver cr = context.getContentResolver();
                InputStream is = null;
                try {
                    is = cr.openInputStream(Uri.parse(fileUri));
                } catch (FileNotFoundException e) {
                    Log.d("xyz", e.toString());
                }
                FileServerAsyncTask.copyFile(is, stream);
                Log.d("xyz", "Client: Data written");
            } catch (IOException e) {
                Log.e("xyz", e.getMessage());
            } finally {
                if (socket != null) {
                    if (socket.isConnected()) {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            // Give up
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

socket.connect((new InetSocketAddress(host, port)),
SOCKET_TIMEOUT);创建Socket连接

    /*returns an output stream to write data into this socket*/
                OutputStream stream = socket.getOutputStream();
                ContentResolver cr = context.getContentResolver();
                InputStream is = null;
                try {
                    is = cr.openInputStream(Uri.parse(fileUri));
                } catch (FileNotFoundException e) {
                    Log.d("xyz", e.toString());
                }
                FileServerAsyncTask.copyFile(is, stream);

将is copy到stream中ok这样我们的服务就启动成功了,至于怎么接收先不细讲,先看一下AsyncTask
2、服务器端 AsyncTask的编写

public class FileServerAsyncTask extends
        AsyncTask<Void, Void, String> {

    private Context context;
    private TextView statusText;

    /**
     * @param context
     * @param statusText
     */
    public FileServerAsyncTask(Context context, View statusText) {
        this.context = context;
        this.statusText = (TextView) statusText;
    }

    @Override
    protected String doInBackground(Void... params) {
        try {
            Log.i("xyz", "file doinback");
            ServerSocket serverSocket = new ServerSocket(8988);
            Socket client = serverSocket.accept();
            final File f = new File(
                    Environment.getExternalStorageDirectory() + "/"
                            + "com.miko.zd" + "/wifip2pshared-"
                            + System.currentTimeMillis() + ".jpg");

            File dirs = new File(f.getParent());

            if (!dirs.exists())
                dirs.mkdirs();
            f.createNewFile();


                /*Returns an input stream to read data from this socket*/
            InputStream inputstream = client.getInputStream();
            copyFile(inputstream, new FileOutputStream(f));
            serverSocket.close();
            return f.getAbsolutePath();

        } catch (IOException e) {
            Log.e("xyz", e.toString());
            return null;
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(String result) {

        Log.i("xyz", "file onpost");
        Toast.makeText(context, "result"+result, Toast.LENGTH_SHORT).show();

        if (result != null) {
            statusText.setText("File copied - " + result);
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse("file://" + result), "image/*");
            context.startActivity(intent);
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see android.os.AsyncTask#onPreExecute()
     */
    @Override
    protected void onPreExecute() {

    }


    public static boolean copyFile(InputStream inputStream, OutputStream out) {
        byte buf[] = new byte[1024];
        int len;
        try {
            while ((len = inputStream.read(buf)) != -1) {
                out.write(buf, 0, len);

            }
            out.close();
            inputStream.close();
        } catch (IOException e) {
            return false;
        }
        return true;
    }
}

AsyncTask原理大家应该很清楚这里不细说,不懂Google=_=+///
ok先看doInbackGround
ServerSocket serverSocket = new ServerSocket(8988);创建Socket
Socket client = serverSocket.accept();这句很关键,
accept方法
Waits for an incoming request and blocks until the connection is opened.
This method returns a socket object representing the just opened connection.
也就说等待连接之前这里是阻塞的,线程停止,当然不会调用下面的onPostExecute,
这一点很关键我们梳理一下,找到设备,点击设备进行连接后ConnectionInfoListener监听器触发,调用方法

onConnectionInfoAvailable{
 if (info.groupFormed && info.isGroupOwner) {
                    Log.i("xyz", "owmer start");

                    mServerTask = new FileServerAsyncTask(MainActivity.this, view);
                    mServerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                    }
                    }

这个时候Task就启动了,当然它会在 Socket client = serverSocket.accept()这里阻塞

这个时候,我们点击发送数据按钮启动服务,socket.connect((new InetSocketAddress(host, port)),
SOCKET_TIMEOUT);
这时候创建连接,阻塞取消,然后就会尽心之后的copy保存了

ok博主是大二党,计算机科学与技术专业,这搞笑的专业,完全自学,每天学一点,好吧这一点有时候是10个钟头,但自己就能感觉到进步,起码打字快了吧=——=,虽然blog很耗费时间,但我坚信这是一种学习的好方法。

  • 26
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
软件介绍:   大家知道为什么迅雷下载那么快么?而且在他高速下载时我们其他程序的网速都慢得可怜?其实,迅雷在我们下载文件的同时(或机器空闲时)都会向其他下载者上传我们已经下载回来的数据,这样,下载者的速度就有了很大的保证,我自己用的是ADSL,有时迅雷上传的速度高达70K/S,对于ADSL来说,这 70K/S的上传速度足以让我放弃任何其他的网络应用了…   随着宽频网络的日益普及,使用各类下载软件(如:BT、迅雷、eDonkey、eMule..等等)的人越来越多,但是在使用此类软件时,通常会因他们的高速而「榨干」了我们有限的带宽,其他需要透过网络来联机的应用程序就几乎动弹不得了!有时想一边下载一边浏览网页都不行,蜗牛般的页面打开速度和极高速的文件下载速度总是让电脑使用者在一旁哭笑不得…   那么,有没有软件可以让高速下载的怪物们分回一点带宽给我们的浏览器呢?有的! NetLimiter 就是您要的,它不仅可以控制某个应用程序的上传/下载使用带宽,还可以实时监控所其占用的带宽,甚至于,你可以限制你的电脑的总上传/下载带宽!网络速度分配完全随心所欲~   这个个头才3M的家伙,不仅可以让你随心的分配有限的网络带宽,他还能帮你楸出占用你大量带宽的元凶呢~(例如某些木马、间谍程序、流氓软件、病毒等等),现在你可以通过他完全掌握你的网络传输情况了~   原来下载速度对网页浏览影响不大的,影响最大的是上传速度,嘿嘿,现在我用他限制了迅雷的上传速度后,即使下载速度高达200K/s,都还能很流畅的浏览网页呢。。。   Netlimiter的使用方法很简单,双击系统栏上的图标启动程序即可,如果你正在使用ie浏览器浏览网页或使用迅雷等下载工具在下载文件,在 Netlimiter窗口中的“connection”处就会出现相应的项目。选中它,我们可以很详细地查看到该程序的下载(dwon rate)或上传(up rate)速度以及已经下载或上传文件的大小等信息。要想限制它的下载或上传速度,只要选中“down limit”或“up limit”复选框,并单击旁边的微调按钮设置下载或上传的最快速度(如图)。经过以上设置后,指定程序的下载或上传速度就会逐渐地上升或下降并最终达到指定的速度。
miko_service_tool_pro 是一款用于手机维修和调试的工具,本教程将向您介绍如何使用该工具。 首先,您需要将该工具安装到您的电脑上。您可以从官方网站下载安装程序,并按照提示完成安装。 安装完成后,双击桌面上的图标或在开始菜单中找到该工具并打开。 接下来,您需要连接您要调试或维修的手机到电脑上。使用一根USB数据线将手机与电脑连接起来。确保手机已开启调试模式,并已安装相关USB驱动程序。 一旦您的手机成功连接到电脑上,打开 miko_service_tool_pro 工具。您将看到一个用户界面,显示出手机的一些基本信息,例如型号、系统版本等。 在工具的菜单栏中,您可以选择不同的操作,例如备份手机数据、刷入ROM、重启手机等。请根据您的需求选择相应的操作。 当您选择某个操作时,工具会提示您进行一些设置或确认。请按照提示进行操作,并确保您的手机充电电量充足,避免在操作过程中手机电量不足导致操作失败。 完成所有设置后,点击“开始”按钮,工具将开始执行相应的操作。请耐心等待操作完成。在操作过程中,请不要断开手机与电脑之间的连接,以免影响操作的进行。 一旦操作完成,您可以在工具的界面中查看相关操作的结果或反馈。如有需要,您还可以选择其他操作进行进一步的调试或维修。 在使用 miko_service_tool_pro 工具时,请务必谨慎操作,并参考官方文档或相关教程以获取更详细的说明。希望本教程能帮助您了解如何使用该工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值