Java Socket 发送数据给ServerSocket失败

oogh
  • 222

需求
通过 adb forward tcp:localport tcp:remoteport 进行端口转发,实现 PC(客户端)Android(服务端) 进行 Socket 通信

PC端
PC端使用的是JavaFX编写的界面,在其Controller中的代码是:

    public class ImageController {
    
        public void onButtonClicked(ActionEvent event) {
            try {
                Runtime.getRuntime().exec("adb forward tcp:10000 tcp:20000");
            
                Socket client = new Socket(InetAddress.getByName("127.0.0.1"), 10000);
                // 向服务端发送消息: hello
                OutputStream out = client.getOutputStream();
                out.write("hello".getBytes());
                out.flush();
            
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

Android服务端

/**
    接收客户端
*/
public class PCService extends Service {
    private static final int SERVER_PORT = 20000;
    
    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(() -> doListening()).start();
    }
    
    private void doListening() {
        try {
            ServerSocket server = new ServerSocket(SERVER_PORT);
            Log.i(TAG, "服务器监听中....");
            Socket client = server.accept();
            new Thread(new SocketIO(client)).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

SocketIO 客户端连接成功后,进行处理的类,继承Runnable

class SocketIO implements Runnable {
    private Socket mClient;

    public SocketIO(Socket client) {
        mClient = client;
    }

    @Override
    public void run() {
        if (mClient.isConnected()) {
            try {
                // 接收客户端发来的消息
                InputStream in = mClient.getInputStream();
                Scanner scan = new Scanner(in);
                scan.useDelimiter("\\A");
                String msg = scan.hasNext() ? scan.next() : "暂无";
                
                System.out.println("接收到的数据: " + msg);

                switch (msg) {
                    case "hello":
                        // TODO: doSomething();
                       break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG, "客户端未连接");
        }
    }
}

问题

  1. PC端,out.flush() 之后不写任何东西是,点击按钮,Android服务端没有任何显示,当关闭PC端应用程序时, Android服务端显示 -> 接收到数据: hello
  2. out.flush() 之后添加 client.shutdownOutputStream() 后, Android服务端显示 -> 接收到数据: 暂无 (意思就是没有收到PC端发来的消息)

想要得到的帮助

  1. 如何解决上面的通信问题? PC端发送一条消息给Android端, Android根据消息内容作出响应返回给PC端?
回复
阅读 2.8k
1 个回答

你想写一个通讯程序,可以先试在在普通java工程中写好,再移植到android工程上。

这是官方指导文档
https://docs.oracle.com/javas...

也可以看看别的代码参考下。如http://cs.lmu.edu/~ray/notes/...

你这段代码的主要问题在你使用的Scanner,Sacnner在读取流的时候不会主动刷新。
客户端发过来的数据,始终在缓冲区中,当tcp链接异常关闭时才会被刷新。
如果服务段相关读取数据替换成下面这样,可以正常显示客户端发过来的数据。

  int len = in.available();
byte [] bys  =new byte[len];
int readbytes = in.read(bys);
if(readbytes!=0)
{
    String res= new String(bys);
    System.out.println(res);
}

问题1与问题2,因为调用client.shutdownOutputStream()后,tcp会出送rst包。收到rst包的服务器端,会丢弃缓冲区的数据。如果不调用,tcp会发送fin包,服务器收到fin包,知道要结束了,于是主动刷新Scanner,准备退出。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏