qq_35383077
qq_35383077
采纳率75%
2016-06-22 03:50

为什么我android UDP通信 只能发信息接收不到信息。请大神帮忙

已采纳

主进程

import android.support.v7.app.ActionBarActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class YuntuActivity extends ActionBarActivity implements OnClickListener {

private TextView adSpeed;
private TextView reSpeed;
private TextView reTxt;
private Button btnHeadCar;
private Button btnAgree;
private Button btnApply;
private Button btnStart;
private Button btnExit;

//自定义变量
private String remoteIP = null;
private int rePort = 0;
private int loPort = 0;
private UDPThread reTxtThread = null;
private UDPThread adSpeedThread = null;
private UDPThread reSpeedThread = null;
private String sendStr = null;//发送的字符串
private String receStr = null;


Handler mhander = new Handler() {

    public void handleMessage(Message msg) {

        Bundle bundle =new Bundle();
        bundle = msg.getData();
        receStr = bundle.getString("info");
        reTxt.setText(receStr);
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_yuntu);

    //初始化UI
    initUI();

    //初始化
    init();

    reTxtThread = new UDPThread(mhander);

}

private void init() {
    remoteIP = "172.22.130.124";
    rePort = 8801;
    loPort = 8805;
}

//初始化UI
private void initUI() {
    adSpeed =(TextView)findViewById(R.id.AdSpeed);
    reSpeed =(TextView)findViewById(R.id.ReSpeed);
    reTxt =(TextView)findViewById(R.id.reTxt);
    btnHeadCar =(Button)findViewById(R.id.button1);
    btnAgree =(Button)findViewById(R.id.button2);
    btnApply =(Button)findViewById(R.id.button3);
    btnStart =(Button)findViewById(R.id.button4);
    btnExit =(Button)findViewById(R.id.button5);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
    //点击  同意入队  按钮
    case R.id.button1:
        sendStr = "you can join in flownteam.";
        if(!sendStr.trim().equals("")) {
            reTxtThread.sendData(sendStr);
        }
        break;  

        //点击 申请入队按钮
    case R.id.button2:
        sendStr = "Can I join in?";
        if(!sendStr.trim().equals("")) {
            reTxtThread.sendData(sendStr);
        }
        break;  

        //点击申请离队按钮
    case R.id.button3:
        sendStr = "Can I exit?";
        if(!sendStr.trim().equals("")) {
            reTxtThread.sendData(sendStr);
        }
        break;  

        //点击开始监听按钮
    case R.id.button4:
        reTxtThread.setReomteIP(remoteIP);

        reTxtThread.setRePort(rePort);

        reTxtThread.setLoPort(loPort);

        boolean connResult = reTxtThread.connectSocket();

        if(connResult) {
            Toast.makeText(getApplicationContext(), "链接建立完毕!", Toast.LENGTH_SHORT).show();
        }

        break;          

        //点击关闭监听按钮  
    case R.id.button5:
            reTxtThread.disConnectSocket();
            Toast.makeText(getApplicationContext(), "链接已经关闭!", Toast.LENGTH_SHORT).show();

        break;
    default:
        break;
    }
}

}

子线程:接收和发送UDP包
package com.example.cqput_yuntu2;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.TextView;

public class UDPThread implements Runnable {

// 定义变量
private TextView rTextView = null;
private String reomteIP = null;
private int rePort = 0;
private int loPort = 0;
private Thread rThread = null;
private static String CHARECTER = "UTF-8";
private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

// 接收
private byte[] rBuffer = new byte[1024];
private DatagramSocket rSocket = null;
private DatagramPacket rPacket = null;
private String rStr = null;

// 发送
private DatagramSocket sSocket = null;
private DatagramPacket sPacket = null;
private byte[] sBuffer = new byte[1024];
public Handler mhandler;

public UDPThread(Handler handler) {
    mhandler = handler;
}

@Override
public void run() {
    // 开始接收数据
    Looper.prepare();
    if (Thread.currentThread() == rThread) {
        System.out.println("------jieshouqian");
        rStr = receiveData();
        System.out.println("------jieshouhou");
        Message toMain = mhandler.obtainMessage();

        Bundle bundle = new Bundle();
        bundle.putString("info", rStr);
        toMain.setData(bundle);
        mhandler.sendMessage(toMain);

    }
    ;
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

// 开始接收数据
private String receiveData() {
    try {
        ByteArrayInputStream bais = new ByteArrayInputStream(rBuffer);
        DataInputStream dis = new DataInputStream(bais);
        if (rSocket == null) {
            rSocket = new DatagramSocket(8805);
        }
        if (rPacket == null) {
            rPacket = new DatagramPacket(rBuffer, rBuffer.length);
        }
        System.out.println("----rece");
        rSocket.receive(rPacket);
        System.out.println("------receHou");
        rStr = dis.readUTF().trim();
        System.out.println("------jieBeg");
        rStr = String.format("[%s:%d//%s]%s", rPacket.getAddress()
                .getHostAddress(), rPacket.getPort(), sdf
                .format(new Date()), rStr);

        return rStr;
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("-----------------recvdata error:"
                + e.getMessage());
    }
    return null;
}

// 建立连接
public boolean connectSocket() {
    boolean result = false;

    // 开启一个新的线程
    startThread();
    System.out.print("监听线程开启");
    result = true;

    return result;
}

// 关闭连接
public void disConnectSocket() {
    if (rSocket != null) {
        rSocket.close();
        rSocket = null;
    }

    if (rPacket != null) {
        rPacket = null;
    }

    // 关闭线程
    stopThread();
}

// 关闭线程
private void stopThread() {
    if (rThread != null) {
        rThread.stop();
        rThread = null;
    }
}

// 开启新的线程
private void startThread() {
    if (rThread == null) {
        rThread = new Thread(this);
        rThread.start();
    }
}

// 开始发送数据
public void sendData(String sendStr) {

    try {
        // 包装数据
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        dos.writeUTF(sendStr);
        sBuffer = baos.toByteArray();
        if (sSocket == null) {
            sSocket = new DatagramSocket();
        }
        if (sPacket == null) {
            sPacket = new DatagramPacket(sBuffer, sBuffer.length,
                    InetAddress.getByName(reomteIP), rePort);
        }
        sSocket.send(sPacket);
        sSocket.close();
        sSocket = null;
        sPacket = null;
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        sSocket.close();
        sSocket = null;
        sPacket = null;
        System.out.println("senddata error:" + e.getMessage());
    }
}

public void setReomteIP(String reomteIP) {
    this.reomteIP = reomteIP;
}

public void setRePort(int rePort) {
    this.rePort = rePort;
}

public void setLoPort(int loPort) {
    // this.loPort = loPort;
}

}

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • wenbodong wenbodong 5年前

    remoteIP = "172.22.130.124";
    rePort = 8801;
    loPort = 8805;
    这IP应该是Internet上的某个主机吧,若手机与其不在同一局域网中(无论是3、4G还是连接热点,都要至少经过一层网关才能接入Internet,而网关一般都会对局域网内设备有保护。
    这里你开启的8801监听,默认情况下只有局域网内设备能访问它。除非你使用该端口向Internet上的主机发送消息,网关在将该消息转发出WAN口时,会为你临时打开一个端口映射,此时该消息的目标主机才可以在外网访问你开的这8801端口。更详细的原理,可以搜索“NAT穿透”。
    简言之,在局域网中使用UDP与外网主机双向通信,需要使用同一个端口进行收发,且得先使用该端口向外网主机的某端口发消息,才能收到该主机相应端口发的消息。
    另外,代码中收到数据包时解析也有问题,rStr = dis.readUTF().trim();收到的数据包大小是不固定的,而这里直接使用之前建立的输入流,读取整个rBuffer的数据,是不应该的。

    点赞 1 评论 复制链接分享
  • wenbodong wenbodong 5年前

    补充下,刚才这句话说的不准备:除非你使用该端口向Internet上的主机发送消息,网关在将该消息转发出WAN口时,会为你临时打开一个端口映射,此时该消息的目标主机才可以在外网访问你开的这8801端口。
    网关在打开端口映射时,通常在WAN口开的端口并非与LAN主机的端口一致。即LAN主机开个8801端口,向Internet的主机发消息,网关在转发时开了个端口9000。将UDP消息中的端口改为9000,转发出去。Internet上的主机接收到的UDP消息,其中的端口不是8801,而是9000。其若想向LAN主机回消息,目的端口不能用8801,而用9000。

    点赞 评论 复制链接分享