【问题标题】:Android AsyncTask not exectued - Trying to send a message to TCP ServerAndroid AsyncTask 未执行 - 尝试向 TCP 服务器发送消息
【发布时间】:2019-06-24 22:51:26
【问题描述】:

我目前正在尝试从我的 Android 智能手机向树莓派发送消息。 我通过此处给出的示例代码实现了一个 Android 客户端:

Really simple TCP client

我将 ip 地址更改为一个端口,以便它可以与我在 pi 上运行的服务器一起使用。该服务器是用 c 编写的,在切换到 android 之前,我实现了一个 C-Client,它到目前为止工作没有任何问题。

服务器只需要收到一条消息,然后打印并停止,所以很简单。

编辑 3

我为调试和分析创建了新的输出,我现在可能知道什么不起作用。据我所知,SendMessageTask 永远不会被执行。

服务器输出现在是:

成功 - 创建套接字

成功 - 绑定

聆听

成功 - 接受

现在它停止了,“阅读...”永远不会被打印出来! (应该发生在while循环中)

在 Android 中,我收到以下必要的输出:

D/TCP 客户端:C:连接中...

D/TcpOptimizer:TcpOptimizer-ON

--> 连接发生

当我按下发送按钮时:

D/myMessage1:按下按钮

D/myMessage:测试

但我没有收到应该在SendMessageTask 中记录的消息

当我单击断开连接按钮时,服务器会打印:

客户端断开

现在是 Android 日志:

来自服务器的 D/RESPONSE:S:收到的消息:'null'

D/sendMessageTask: 尝试发送消息

D/TcpClient: 无法发送 --> mBufferOut 为空

因此我的猜测是,SendMessageTask 永远不会运行,直到由于断开连接而失败,但为什么呢?

编辑 3 - 结束

这是(已编辑的)服务器代码:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>


int main(){
    int welcomeSocket, newSocket, read_size;
    char buffer[10000];
    struct sockaddr_in serverAddr;
    struct sockaddr_storage serverStorage;
    socklen_t addr_size;

    /*---- Create the socket. The three arguments are: ----*/
    /* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
    welcomeSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (welcomeSocket == -1)    {
        printf("Could not create socket\n");
    }else {
        printf("Success - create socket\n");
    }

    /*---- Configure settings of the server address struct ----*/
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(7891);
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    /* Set all bits of the padding field to 0 */
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);

    /*---- Bind the address struct to the socket ----*/
    if(bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0){
        printf("Error - Binding\n");
    }else {
        printf("Success - Binding\n");
    }

    /*---- Listen on the socket, with 5 max connection requests queued ----*/
    if(listen(welcomeSocket,5)==0)
        printf("Listening\n");
    else
        printf("Error\n");

    /*---- Accept call creates a new socket for the incoming connection ----*/
    addr_size = sizeof serverStorage;
    newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
    if(newSocket < 0){
        printf("Error - Accept\n");
    }else {
        printf("Success - Accept\n");
    }

    while( (read_size = recv(newSocket, buffer, 10000, 0)) > 0){
        write(newSocket, buffer, strlen(buffer));
        printf("reading...");
    }

    if(read_size == 0){
        printf("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1){
        printf("Error - recv failed");
    }
    return 0;
}

我不太确定里面的参数

welcomeSocket = socket(AF_INET, SOCK_STREAM, 0);

仍然正确吗?

Android 中的客户端代码是:

import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class TcpClient {

    public static final String TAG = TcpClient.class.getSimpleName();
    public static final String SERVER_IP = "192.168.4.1"; //server IP address
    public static final int SERVER_PORT = 7891;
    // message to send to the server
    private String mServerMessage;
    // sends message received notifications
    private OnMessageReceived mMessageListener = null;
    // while this is true, the server will continue running
    private boolean mRun = false;
    // used to send messages
    private PrintWriter mBufferOut;
    // used to read messages from the server
    private BufferedReader mBufferIn;

    /**
     * Constructor of the class. OnMessagedReceived listens for the messages received from server
     */
    public TcpClient(OnMessageReceived listener) {
        mMessageListener = listener;
    }

    /**
     * Sends the message entered by client to the server
     *
     * @param message text entered by client
     */
    public void sendMessage(final String message) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (mBufferOut != null) {
                    Log.d(TAG, "Sending: " + message);
                    mBufferOut.println(message);
                    mBufferOut.flush();
                }else{
                    Log.d(TAG, "Cannot send --> mBufferOut is null");
                }
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }

    /**
     * Close the connection and release the members
     */
    public void stopClient() {

        mRun = false;

        if (mBufferOut != null) {
            mBufferOut.flush();
            mBufferOut.close();
        }

        mMessageListener = null;
        mBufferIn = null;
        mBufferOut = null;
        mServerMessage = null;
    }

    public void run() {

        mRun = true;

        try {
            //here you must put your computer's IP address.
            InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

            Log.d("TCP Client", "C: Connecting...");

            //create a socket to make the connection with the server
            Socket socket = new Socket(serverAddr, SERVER_PORT);

            try {

                //sends the message to the server
                mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);


                //receives the message which the server sends back
                mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));


                //in this while the client listens for the messages sent by the server
                while (mRun) {
                    /*
                    mServerMessage = mBufferIn.readLine();

                    if (mServerMessage != null && mMessageListener != null) {
                        //call the method messageReceived from MyActivity class
                        mMessageListener.messageReceived(mServerMessage);
                    }
*/
                }

                Log.d("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");

            } catch (Exception e) {
                Log.e("TCP", "S: Error", e);
            } finally {
                //the socket must be closed. It is not possible to reconnect to this socket
                // after it is closed, which means a new socket instance has to be created.
                socket.close();
            }

        } catch (Exception e) {
            Log.e("TCP", "C: Error", e);
        }

    }

    //Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
    //class at on AsyncTask doInBackground
    public interface OnMessageReceived {
        public void messageReceived(String message);
    }

}

我的(已编辑的)Mainactivity 包括用于连接的 AsyncTask 是

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;

public class MyActivity extends AppCompatActivity {

    private TextView mTextMessage;
    private TextView myAwesomeTextView;

    private TcpClient mTcpClient;

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    mTextMessage.setText(R.string.title_home);
                    return true;
                case R.id.navigation_dashboard:
                    mTextMessage.setText(R.string.title_dashboard);
                    return true;
                case R.id.navigation_notifications:
                    mTextMessage.setText(R.string.title_notifications);
                    return true;
            }
            return false;
        }
    };

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

        mTextMessage = (TextView) findViewById(R.id.message);
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

        myAwesomeTextView = (TextView)findViewById(R.id.editText);

        //TCP connect
        new ConnectTask().execute("");

        //Buttons
        final Button button_Send = findViewById(R.id.button_Send);
        button_Send.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                //Set text (debugging)
                myAwesomeTextView.setText("My Awesome Text");
                Log.d("myMessage1", "button pushed ");

                //sends the message to the server
               String message = "testing\0";
                //String message = "testing\n\r";

                if (mTcpClient != null) {
                    new SendMessageTask().execute(message);

                    //not needed just for debugging
                    Log.d("myMessage", "testing ");
                }

            }
        });

        final Button button_Disconnect = findViewById(R.id.button_Disconnect);
        button_Disconnect.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                if (mTcpClient != null) {
                    mTcpClient.stopClient();
                }

            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mTcpClient != null) {
            // disconnect
            new DisconnectTask().execute();
        }

    }

    /**
     * Sends a message using a background task to avoid doing long/network operations on the UI thread
     */
    public class SendMessageTask extends AsyncTask<String, Void, Void> {

        @Override
        protected Void doInBackground(String... params) {

            // send the message
            mTcpClient.sendMessage(params[0]);

            Log.d("sendMessageTask", "try to send message ");


            return null;
        }

        @Override
        protected void onPostExecute(Void nothing) {
            super.onPostExecute(nothing);

            //nothing to do yet
        }
    }

    /**
     * Disconnects using a background task to avoid doing long/network operations on the UI thread
     */
    public class DisconnectTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... voids) {

            // disconnect
            mTcpClient.stopClient();
            mTcpClient = null;

            return null;
        }

        @Override
        protected void onPostExecute(Void nothing) {
            super.onPostExecute(nothing);

            //nothing to do yet
        }
    }

    public class ConnectTask extends AsyncTask<String, String, TcpClient> {

        @Override
        protected TcpClient doInBackground(String... message) {

            //we create a TCPClient object and
            mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
                @Override
                //here the messageReceived method is implemented
                public void messageReceived(String message) {
                    //this method calls the onProgressUpdate
                    publishProgress(message);
                }
            });
            mTcpClient.run();

            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);

            Log.d("test", "response " + values[0]);
            //process server response here....
        }
    }
}

EDIT #2(失败的行为仍然存在)

  • 在 TcpClient 的运行方法中取消注释的 while(mRun) 循环 --> 认为套接字可能在消息发送之前被 finally 关闭。

  • 将初始连接移到 onCreate() 中,所以按钮只会 处理发送并建立之前的连接。

  • 删除发送消息后关闭套接字

【问题讨论】:

  • 您忘记检查大多数服务器程序中的错误,包括检查“连接关闭”(我相信这里发生了什么)。而且您不会终止您阅读的“字符串”。
  • 感谢您的回复,我应该在我的代码中的哪个位置检查连接是否关闭?像打印消息后一样?终止字符串意味着“\n”?抱歉,我对这些东西很陌生。
  • 在 C 中,char 字符串实际上称为 null-terminated 字节字符串。您需要将该 null-terminator 添加到您读取的字符串中。至于另一个问题,请阅读 C 源代码中所有函数的手册页。还有一些网络编程教程。他们都应该告诉你你需要知道的一切。
  • 好的,谢谢你,我会在完成后提供答案或进一步的问题。
  • 我想我应该应用您提到的所有更改,但输出仍然没有发送的文本消息。我还提供了 android 给我的输出,我看不出这里有什么问题吗?服务器只打印一条空消息并关闭,就像他收到一个空字符串一样。我不太确定“\0”在“Java”中的含义是否与在 c 中的含义相同?但我的猜测是,c-server 读取它以便它可以工作?

标签: android c tcp client-server


【解决方案1】:

我设法让这个工作。

我换行了

new SendMessageTask().execute(message);

new SendMessageTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message);

这使发送工作正常。

我也把服务器代码改成了这样:

#define MAX 2048
#define PORT 7891
#define SA struct sockaddr

// Function designed for chat between client and server.
void communicate(int sockfd)
{
    char buff[MAX];
    int n;
    // infinite loop for chat
    for (;;) {
        bzero(buff, MAX);

        // read the message from client and copy it in buffer
        read(sockfd, buff, sizeof(buff));
        // print buffer which contains the client contents
        printf("From client: %s\t To client : ", buff);
        bzero(buff, MAX);
        n = 0;
        // copy server message in the buffer
        while ((buff[n++] = getchar()) != '\n');

        // and send that buffer to client
        write(sockfd, buff, sizeof(buff));

        // if msg contains "Exit" then server exit and chat ended.
        if (strncmp("exit", buff, 4) == 0) {
            printf("Server Exit...\n");
            break;
        }

    }
}

// Driver function
int main()
{
    int sockfd, connfd, len;
    struct sockaddr_in servaddr, cli;

    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");
    bzero(&servaddr, sizeof(servaddr));

    // assign IP, PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    // Binding newly created socket to given IP and verification
    if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully binded..\n");

    // Now server is ready to listen and verification
    if ((listen(sockfd, 5)) != 0) {
        printf("Listen failed..\n");
        exit(0);
    }
    else
        printf("Server listening...\n");
    len = sizeof(cli);

    // Accept the data packet from client and verification
    connfd = accept(sockfd, (SA*)&cli, &len);
    if (connfd < 0) {
        printf("server acccept failed...\n");
        exit(0);
    }
    else
        printf("server acccept the client..\n");

    // Function for chatting between client and server
    communicate(connfd);

    // After chatting close the socket
    if(close(sockfd) < 0){
        printf("Error - closing socket...\n");
    }
    else{
        printf("Socket successfully closed..\n");
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-20
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 2019-12-06
    • 2012-10-04
    • 1970-01-01
    相关资源
    最近更新 更多