Отправка и получение данных на UDP Socket java android

Я могу правильно отправлять свои данные через сокет UDP, но когда я получаю данные, они продолжают ждать при получении команды, я не знаю, что это вызывает. Пожалуйста, взгляните на мой код ниже.

Я могу правильно получать данные на стороне сервера с устройства Android, но когда я отправляю данные со стороны сервера на устройство Android, они не получают. но когда я отправляю данные с сервера любому другому клиенту, например, приложению для ПК, он получает и правильно отображает данные.

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)
        {

        }
    }
}

person user2539602    schedule 23.10.2013    source источник
comment
Я знаю, что это уже немного устарело, но вы когда-нибудь догадались об этом? Застрял на той же проблеме, что и ты. Я получаю данные на сервер, но ничего не отправляю обратно ...   -  person patrickdamery    schedule 04.02.2015
comment
попробуйте уменьшить размер данных для каждой отправки в случае UDP, это решило проблему для меня.   -  person user2539602    schedule 04.02.2015
comment
Я понял это через некоторое время, но размер данных должен быть одинаковым как на отправляющей, так и на принимающей стороне, иначе вы можете получить прерывистый звук.   -  person patrickdamery    schedule 30.03.2015


Ответы (2)


Документация в Eclipse:

Получает пакет из этого сокета и сохраняет его в пакете аргументов. Все поля пакета должны быть настроены в соответствии с полученными данными. Если полученные данные длиннее, чем размер буфера пакетов, они обрезаются. Этот метод блокируется до тех пор, пока не будет получен пакет или не истечет время ожидания.

Команда «s.receive(p);» блокирует поток до тех пор, пока он не получит данные или пока не истечет время ожидания, установленное с помощью setSoTimeout (тайм-аут).

Я сделал 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)" или что-то в этом роде.

person Tim    schedule 23.10.2013
comment
Я получаю сообщение об ошибке «Не удается разрешить символ Main» в таких случаях, как Main.BroadcastAddress и Main.SERVER_PORT. Есть ли способ исправить это? - person ksivakumar; 19.04.2017
comment
Это 2 константы, которые я объявил в другом файле .java (называемом Main). Вы можете просто заменить их теми значениями, которые вам нужны. - person Tim; 20.04.2017
comment
Как бы вы позвонили Main.MainContext.getApplicationContext (). SendBroadcast (i); в первом классе без использования класса Main? - person ksivakumar; 20.04.2017
comment
Я использую Main только для получения контекста моего приложения (getApplicationContext ()). Вы можете написать конструктор для класса UDP_Server и передать контекст конструктору. Что-то вроде общедоступного UDP_Server (Context AppContext), а затем сохраните ссылку на контекст в переменной MyAppContext в классе UDP_Server. После этого вы можете вызвать MyAppContext.sendBroadcast (i); и все должно быть в порядке. Вот сообщение, в котором показано, что я пытаюсь объяснить: stackoverflow.com/a/16921076/1837824 - person Tim; 21.04.2017
comment
Не работает в эмуляторе. 2 эмулятора на одном компьютере. используя ip и порт. - person Koustuv Ganguly; 10.06.2019

Здесь, в этом посте, вы найдете подробный код для установки сокета между устройствами или между двумя приложениями на одном и том же мобильном телефоне.

Вы должны создать два приложения для тестирования кода ниже.

В файле манифеста обоих приложений добавьте разрешение ниже

<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_width="match_parent"
    android:layout_height="match_parent">

    <TableRow
        android:id="@+id/tr_send_message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        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_width="0dp"
            android:layout_height="wrap_content"
            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_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:text="Send" />
    </TableRow>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        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_width="match_parent"
            android:layout_height="wrap_content"
            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_width="match_parent"
    android:layout_height="match_parent">

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

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        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_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" />
    </ScrollView>

    <Button
        android:id="@+id/btn_start_receiving"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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;
        }
    }
}
person Girish Bhalerao    schedule 04.05.2017
comment
это хорошо, но он получает только 1 строку, тогда вам нужно остановить сервер, перезапустить его и отправить снова, чтобы получить новую строку - person ; 02.02.2018
comment
В UDP лучше не звонить как сервер и клиент. Отправитель и получатель хорошо подходят для именования. - person ilkayaktas; 22.02.2019