在UDP Socket java android上发送和接收数据

Posted

技术标签:

【中文标题】在UDP Socket java android上发送和接收数据【英文标题】:Send and receive data on UDP Socket java android 【发布时间】:2013-11-01 16:07:34 【问题描述】:

我能够通过 UDP 套接字正确发送我的数据,但是当我收到数据时,它一直在等待接收命令,我不知道是什么原因造成的。 请看下面我的代码。

我能够在服务器端从 android 设备正确接收数据,但是当我从服务器端向 android 设备发送数据时它没有接收到。但是当我将数据从服务器发送到任何其他客户端(例如 PC 应用程序)时,它会正确接收并显示数据。

class Task implements Runnable 
    @Override
    public void run() 
        try 
            String messageStr = "feed";
            int server_port = 8888;
            InetAddress local = InetAddress.getByName("10.0.2.2");
            int msg_length = messageStr.length();
            byte[] message = messageStr.getBytes();


            DatagramSocket s = new DatagramSocket();
           // 

            DatagramPacket p = new DatagramPacket(message, msg_length, local, server_port);
            s.send(p);//properly able to send data. i receive data to server

            for (int i = 0; i <= 20; i++) 
                final int value = i;
                message = new byte[30000];
                p = new DatagramPacket(message,message.length );
                s.receive(p); //keeps on waiting here but i am sending data back from server, but it never receives
                final byte[] data =  p.getData();;
                try 



                    Thread.sleep(1000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                handler.post(new Runnable() 
                    @Override
                    public void run() 
                        progressBar.setProgress(value);
                        imageView.setImageBitmap(BitmapFactory.decodeByteArray(data,0,data.length));
                    
                );
            
        
        catch(Exception ex)
        

        
    

【问题讨论】:

我知道这已经有点老了,但你有想过这个吗?卡在和你一样的问题上。我正在将数据发送到服务器,但是当我什么都不发回时.. 在 UDP 的情况下尝试减少每次发送的数据大小,这解决了我的问题。 一段时间后我想通了,但是发送端和接收端的数据大小必须相同,否则会出现断断续续的音频 【参考方案1】:

Eclipse 中的文档:

从这个套接字接收一个数据包并将其存储在参数包中。 pack 的所有字段都必须根据接收到的数据进行设置。如果 接收到的数据长于被截断的数据包缓冲区大小。 此方法阻塞,直到收到数据包或超时 过期了。

s.receive(p);”命令阻塞线程,直到它收到数据或用 setSoTimeout(timeout) 设置的超时结束。

我已经做了 2 节课来进行交流。 第一个 UDP 服务器:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;

public class UDP_Server 

    private AsyncTask<Void, Void, Void> async;
    private boolean Server_aktiv = true;

    @SuppressLint("NewApi")
    public void runUdpServer() 
    
        async = new AsyncTask<Void, Void, Void>() 
        
            @Override
            protected Void doInBackground(Void... params)
               
                byte[] lMsg = new byte[4096];
                DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
                DatagramSocket ds = null;

                try 
                
                    ds = new DatagramSocket(Main.SERVER_PORT);

                    while(Server_aktiv)
                    
                        ds.receive(dp);

                        Intent i = new Intent();
                        i.setAction(Main.MESSAGE_RECEIVED);
                        i.putExtra(Main.MESSAGE_STRING, new String(lMsg, 0, dp.getLength()));
                        Main.MainContext.getApplicationContext().sendBroadcast(i);
                    
                 
                catch (Exception e) 
                
                    e.printStackTrace();
                 
                finally 
                
                    if (ds != null) 
                    
                        ds.close();
                    
                

                return null;
            
        ;

        if (Build.VERSION.SDK_INT >= 11) async.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        else async.execute();
    

    public void stop_UDP_Server()
    
        Server_aktiv = false;
    

我将接收到的数据发送到一个 BroadcastReceiver,然后你可以对数据做任何你想做的事情。

现在我的客户发送数据。在这段代码中我发送了一个广播,但我认为更改发送到直接IP或其他东西的代码是没有问题的。

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Build;

public class UDP_Client 

    private AsyncTask<Void, Void, Void> async_cient;
    public String Message;

    @SuppressLint("NewApi")
    public void NachrichtSenden()
    
        async_cient = new AsyncTask<Void, Void, Void>() 
        
            @Override
            protected Void doInBackground(Void... params)
               
                DatagramSocket ds = null;

                try 
                
                    ds = new DatagramSocket();
                    DatagramPacket dp;                          
                    dp = new DatagramPacket(Message.getBytes(), Message.length(), Main.BroadcastAddress, Main.SERVER_PORT);
                    ds.setBroadcast(true);
                    ds.send(dp);
                 
                catch (Exception e) 
                
                    e.printStackTrace();
                
                finally 
                
                    if (ds != null) 
                       
                        ds.close();
                    
                
                return null;
            

            protected void onPostExecute(Void result) 
            
               super.onPostExecute(result);
            
        ;

        if (Build.VERSION.SDK_INT >= 11) async_cient.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        else async_cient.execute();
    

这是从主类实例化类的方法。

            //start UDP server
        Server = new UDP_Server();
        Server.runUdpServer();

        //UDP Client erstellen
        Client = new UDP_Client();

以及如何与客户端发送消息。

                                    //Set message
                Client.Message = "Your message";
                                    //Send message
                Client.NachrichtSenden();

要停止 UDP_Server,只需将 Server.Server_aktiv 设置为 false。

要设置上面的消息,你也可以写一个“setMessage(String message)”方法或类似的东西。

【讨论】:

在 Main.BroadcastAddress 和 Main.SERVER_PORT 等实例中出现错误“无法解析符号 Main”。有没有办法解决这个问题? 这是我在另一个 .java 文件(称为 Main)中声明的 2 个常量。您可以将它们替换为您希望它们具有的值。 如何调用 Main.MainContext.getApplicationContext().sendBroadcast(i);在头等舱中不使用 Main 类? 我只使用“Main”来获取我的应用程序的上下文 (getApplicationContext())。您可以为 UDP_Server 类编写构造函数并将上下文传递给构造函数。类似于“public UDP_Server(Context AppContext)”的东西,然后将上下文的引用保存在 UDP_Server 类的变量“MyAppContext”中。完成此操作后,您可以调用“MyAppContext.sendBroadcast(i);”你应该没事。这是一个帖子,显示了我要解释的内容:***.com/a/16921076/1837824 无法在模拟器中工作。 2个模拟器在同一台电脑上。使用 ip 和端口。【参考方案2】:

在这里,在这篇文章中,您将找到在设备之间或同一手机中的两个应用程序之间建立套接字的详细代码。

你必须创建两个应用程序来测试下面的代码。

在两个应用程序的清单文件中,添加以下权限

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

第一个应用代码:UDP 客户端套接字

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_>

    <TableRow
        android:id="@+id/tr_send_message"
        android:layout_
        android:layout_
        android:gravity="center"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="11dp">

        <EditText
            android:id="@+id/edt_send_message"
            android:layout_
            android:layout_
            android:layout_weight="1"
            android:layout_marginRight="10dp"
            android:layout_marginLeft="10dp"
            android:hint="Enter message"
            android:inputType="text" />

        <Button
            android:id="@+id/btn_send"
            android:layout_
            android:layout_
            android:layout_marginRight="10dp"
            android:text="Send" />
    </TableRow>

    <ScrollView
        android:layout_
        android:layout_
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/tr_send_message"
        android:layout_marginTop="25dp"
        android:id="@+id/scrollView2">

        <TextView
            android:id="@+id/tv_reply_from_server"
            android:layout_
            android:layout_
            android:orientation="vertical" />
    </ScrollView>

</RelativeLayout>

UDPClientSocketActivity.java

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * Created by Girish Bhalerao on 5/4/2017.
 */

public class UDPClientSocketActivity extends AppCompatActivity implements View.OnClickListener 

    private TextView mTextViewReplyFromServer;
    private EditText mEditTextSendMessage;

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

        Button buttonSend = (Button) findViewById(R.id.btn_send);

        mEditTextSendMessage = (EditText) findViewById(R.id.edt_send_message);
        mTextViewReplyFromServer = (TextView) findViewById(R.id.tv_reply_from_server);

        buttonSend.setOnClickListener(this);
    

    @Override
    public void onClick(View v) 

        switch (v.getId()) 

            case R.id.btn_send:
                sendMessage(mEditTextSendMessage.getText().toString());
                break;
        
    

    private void sendMessage(final String message) 

        final Handler handler = new Handler();
        Thread thread = new Thread(new Runnable() 

            String stringData;

            @Override
            public void run() 

                    DatagramSocket ds = null;
                    try 
                        ds = new DatagramSocket();
                        // IP Address below is the IP address of that Device where server socket is opened.
                        InetAddress serverAddr = InetAddress.getByName("xxx.xxx.xxx.xxx");
                        DatagramPacket dp;
                        dp = new DatagramPacket(message.getBytes(), message.length(), serverAddr, 9001);
                        ds.send(dp);

                        byte[] lMsg = new byte[1000];
                        dp = new DatagramPacket(lMsg, lMsg.length);
                        ds.receive(dp);
                        stringData = new String(lMsg, 0, dp.getLength());

                     catch (IOException e) 
                        e.printStackTrace();
                     finally 
                        if (ds != null) 
                            ds.close();
                        
                    

                handler.post(new Runnable() 
                    @Override
                    public void run() 

                        String s = mTextViewReplyFromServer.getText().toString();
                        if (stringData.trim().length() != 0)
                            mTextViewReplyFromServer.setText(s + "\nFrom Server : " + stringData);

                    
                );
            
        );

        thread.start();
    

第二个应用程序代码 - UDP 服务器套接字

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_>

    <Button
        android:id="@+id/btn_stop_receiving"
        android:layout_
        android:layout_
        android:text="STOP Receiving data"
        android:layout_alignParentTop="true"
        android:enabled="false"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="89dp" />

    <ScrollView
        android:layout_
        android:layout_
        android:layout_below="@+id/btn_stop_receiving"
        android:layout_marginTop="35dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

        <TextView
            android:id="@+id/tv_data_from_client"
            android:layout_
            android:layout_
            android:orientation="vertical" />
    </ScrollView>

    <Button
        android:id="@+id/btn_start_receiving"
        android:layout_
        android:layout_
        android:text="START Receiving data"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="14dp" />
</RelativeLayout>

UDPServerSocketActivity.java

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * Created by Girish Bhalerao on 5/4/2017.
 */

public class UDPServerSocketActivity extends AppCompatActivity implements View.OnClickListener 

    final Handler handler = new Handler();

    private Button buttonStartReceiving;
    private Button buttonStopReceiving;
    private TextView textViewDataFromClient;

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

        buttonStartReceiving = (Button) findViewById(R.id.btn_start_receiving);
        buttonStopReceiving = (Button) findViewById(R.id.btn_stop_receiving);
        textViewDataFromClient = (TextView) findViewById(R.id.tv_data_from_client);

        buttonStartReceiving.setOnClickListener(this);
        buttonStopReceiving.setOnClickListener(this);

    

    private void startServerSocket() 

        Thread thread = new Thread(new Runnable() 

            private String stringData = null;

            @Override
            public void run() 

                byte[] msg = new byte[1000];
                DatagramPacket dp = new DatagramPacket(msg, msg.length);
                DatagramSocket ds = null;
                try 
                    ds = new DatagramSocket(9001);
                    //ds.setSoTimeout(50000);
                    ds.receive(dp);

                    stringData = new String(msg, 0, dp.getLength());
                    updateUI(stringData);

                    String msgToSender = "Bye Bye ";
                    dp = new DatagramPacket(msgToSender.getBytes(), msgToSender.length(), dp.getAddress(), dp.getPort());
                    ds.send(dp);

                 catch (IOException e) 
                    e.printStackTrace();
                 finally 
                    if (ds != null) 
                        ds.close();
                    
                
            

        );
        thread.start();
    

    private void updateUI(final String stringData) 

        handler.post(new Runnable() 
            @Override
            public void run() 

                String s = textViewDataFromClient.getText().toString();
                if (stringData.trim().length() != 0)
                    textViewDataFromClient.setText(s + "\n" + "From Client : " + stringData);
            
        );
    

    @Override
    public void onClick(View v) 

        switch (v.getId()) 

            case R.id.btn_start_receiving:

                startServerSocket();

                buttonStartReceiving.setEnabled(false);
                buttonStopReceiving.setEnabled(true);
                break;

            case R.id.btn_stop_receiving:

                //Add logic to stop server socket yourself

                buttonStartReceiving.setEnabled(true);
                buttonStopReceiving.setEnabled(false);
                break;
        
    

【讨论】:

这很好,但它只接收 1 个字符串然后你需要停止服务器并重新启动它并再次发送以获得新字符串 在UDP中最好不要作为服务器和客户端调用。发送者和接收者非常适合命名。

以上是关于在UDP Socket java android上发送和接收数据的主要内容,如果未能解决你的问题,请参考以下文章

一个Android Socket的例子(转)

Android 基于UDP的Socket通信

java 网络编程(Socket) TCP/UDP 总结案例

UDP Socket

android thread / udp socket sample

Android 通过局域网udp广播自动建立socket连接