如何使用套接字从服务器读取数据?

Posted

技术标签:

【中文标题】如何使用套接字从服务器读取数据?【英文标题】:How to use sockets to read data from server? 【发布时间】:2018-11-19 15:41:57 【问题描述】:

应用程序有 MainActivity(包含一个 EditText 和一个 Button)和 DisplayActivity(包含单个 TextView),用户在 EditText 中输入一条消息并按下发送按钮。来自 EditText 的消息字符串被发送到服务器。然后对 DisplayActivity 启动一个新的意图。 DisplayActivity 将使用 readLine() 从服务器读取数据,并根据从服务器接收到的数据设置 TextView。

activity_main.xml 有一个 id="@+id/message_textView" 的 EditText 和 id="@+id/send_button" 的 Button。 DisplayActivity 有 android:id="@+id/displayTextView"。

我向服务器发送数据的代码可以正常工作,但是当我尝试从服务器读取数据时,readline() 只是停在那里并永远坐在那里。

Android 应用有 MainActivity 和 DisplayActivity 类。

我在 eclipse 中运行服务器代码。

服务器代码。

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.net.*;
import java.io.*;

public class MyServer 

     public static void main(String[] args) throws IOException 

         int portNumber = 4442;

         System.out.println("Starting server..");

         try 
             while(true) 
             ServerSocket serverSocket =
                 new ServerSocket(portNumber);
             Socket clientSocket = serverSocket.accept();     
             PrintWriter out =
                 new PrintWriter(clientSocket.getOutputStream(), true);                   
             BufferedReader in = new BufferedReader(
                 new InputStreamReader(clientSocket.getInputStream()));
             String message = in.readLine();
             System.out.println(message);//Just print to console, to test if server got message
             out.println(message);
             serverSocket.close();
             clientSocket.close();
//           out.close();
//           in.close();
             
          catch (IOException e) 
             System.out.println("Exception caught when trying to listen on port "
                 + portNumber + " or listening for a connection");
             System.out.println(e.getMessage());
         
     

主活动

import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

public class MainActivity extends AppCompatActivity 

    static Socket client;
    private PrintWriter printWriter;
    private EditText messageET;
    private Button sendButton;
    private String message;

    static String hostIP = "10.0.2.2";
    static int port = 4442;

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

        messageET = findViewById(R.id.message_textView);
        sendButton = findViewById(R.id.send_button);

        sendButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                message = messageET.getText().toString();
                messageET.setText("");

                MyTask myTask = new MyTask();
                myTask.execute();

                Intent intent = new Intent(getApplicationContext(), DisplayActivity.class);
                startActivity(intent);
            
        );
    

    class MyTask extends AsyncTask<String,Void,String>
    
        @Override
        protected String doInBackground(String... strings) 
            try
            
                client = new Socket(hostIP, port);
                printWriter = new PrintWriter(client.getOutputStream(), true);
                //printWriter.write(message);
                printWriter.println(message);
                //printWriter.flush();
                printWriter.close();
                client.close();
            catch(IOException e)
            
                e.printStackTrace();
            
            return null;
        
    

显示活动

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;


public class DisplayActivity extends AppCompatActivity 

    //final String TAG = "displayactivitylog";
    private Socket socket;
    private BufferedReader bufferedReader;

    private TextView displayTV;
    private String msgReceived = null;

    String hostIP = "10.0.2.2";
    int port = 4442;

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

        displayTV = findViewById(R.id.displayTextView);
        ReadTask readTask = new ReadTask();
        readTask.execute();
    
    class ReadTask extends AsyncTask<String,Void,String>
    
        @Override
        protected String doInBackground(String... strings) 
            String result = "";
            try
            
                //create a new socket and attempt to read from it
                socket = new Socket(hostIP,port);
                bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //*****the app stops on this line, and nothing happens after*****  
                msgReceived = bufferedReader.readLine();
                //************************************ 
//                while((msgReceived = bufferedReader.readLine()) != null)
//                    result += msgReceived;
//                

                bufferedReader.close();
                socket.close();
            catch(IOException e)
            
                e.printStackTrace();
            
            return result;
        
        //update the TextView with the message from the server
        @Override
        protected void onPostExecute(String s) 
            displayTV.setText(s);
            super.onPostExecute(s);
        
    

当我运行调试器时,它实际上只是在 doInBackground() 方法中的 msgReceived = bufferedReader.readLine() 上的 DisplayActivity.java 中停止并且没有给出错误。

我的服务器启动正常,当我将数据从我的应用程序发送到服务器时,在 eclipse 上它会打印出发送的内容(有时由于某种原因为 null)。

---------------解决方案---------------

问题由绿色应用程序回答,但基本上服务器类希望在连接首次打开时读取一些内容,然后发送数据。然而在 ReadTask 中,它所做的只是尝试从服务器读取数据(但它应该先发送数据,然后再从中读取)

更新代码。

MainActivity.java

public class MainActivity extends AppCompatActivity 

    private EditText messageET;
    private Button sendButton;
    static String message;

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

        messageET = findViewById(R.id.message_textView);
        sendButton = findViewById(R.id.send_button);

        sendButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                message = messageET.getText().toString();
                messageET.setText("");

                Intent intent = new Intent(getApplicationContext(), DisplayActivity.class);
                startActivity(intent);
            
        );
    

DisplayActivity.java

public class DisplayActivity extends AppCompatActivity 

    private Socket socket;
    private PrintWriter printWriter;
    private BufferedReader bufferedReader;

    private TextView displayTV;
    private String msgReceived = null;

    String hostIP = "10.0.2.2";
    int port = 4442;

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

        displayTV = findViewById(R.id.displayTextView);
        ReadTask readTask = new ReadTask();
        readTask.execute();
    
    class ReadTask extends AsyncTask<String,Void,String>
    
        @Override
        protected String doInBackground(String... strings) 
            String result = "";
            try
            
                //create a new socket and attempt to write to it first then read from it
                socket = new Socket(hostIP,port);
                //add data to the server
                printWriter = new PrintWriter(socket.getOutputStream(), true);
                printWriter.println(MainActivity.message);
                //get a stream, to be able to read data from the server
                bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                msgReceived = bufferedReader.readLine();
                displayTV.setText(msgReceived);
                //close the socket connections
                printWriter.close();
                bufferedReader.close();
                socket.close();
            catch(IOException e)
            
                e.printStackTrace();
            
            return result;
        
    

【问题讨论】:

它应该停止直到数据到达。 “出于某种原因”是您已到达流的末尾,如 Javadoc 中所述,在套接字的情况下,这意味着对等方关闭了连接,这意味着您必须这样做。 OP,很抱歉在此线程中发帖,因为您的问题已经解决,但我无法重现您收到的“null”消息。 @EJP 也很抱歉占用您的时间,您能否在控制台中解释一下“null”? 它出现在控制台中的唯一情况是,如果message 这一行中的变量printWriter.println(message); 为空。它似乎与套接字打开/关闭问题无关 另一方面,消息来自“EditText”的getText()方法,并且该方法永远不会返回null 【参考方案1】:

你有两个客户端套接字。还有两个 serversocket。

这是一种非常奇怪的方法。

第一个客户端发送一行并关闭连接。当服务器尝试读取该行并且确实如此时,这可以正常工作。然后两者都关闭。

然后你启动第二个客户端。这个连接到一个新的服务器套接字。但是这个客户端直接尝试读取一行。由于服务器还尝试从这个新客户端读取一行,因此两者都将在 readLine() 上等待永恒。

【讨论】:

嘿,在你告诉我出了什么问题后,我修复了它。在 MainActivity.java 我删除了 AsyncTask。在 DisplayActivity.java 中,我向 ReadTask 添加了更多代码(以写入服务器)。 null 也不再出现在服务器中。 干得好。如果您只问...,我会这样建议您的 ;-) 谢谢,我认为问题是我不了解套接字如何工作的概念。我以为我可以打开一个套接字,并从服务器读取数据,就好像它就像一个数据库一样。你也可以检查更新的答案,我的解决方案是正确的/有意义吗? 你发布那张照片让我很开心。谢谢。 你也帮了我很多!我被困了一段时间。谢谢!

以上是关于如何使用套接字从服务器读取数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用套接字通道读取和写入数据并接受连接

TCP套接字服务器如何判断从客户端接收到的数据何时完成?

从套接字读取消息时如何获取字节序?

如何从套接字读取流数据集?

OS X:如何使用 NSRunLoop 观察套接字读取事件?

使用 QT 从套接字读取