java - Android NIO 服务器选择器在没有消息发送时读取

标签 java android sockets

我正在尝试使用 NIO 服务器来读取/写入 TCP 连接的客户端。我已成功建立连接,并且我的初始消息已发送到服务器并得到正确处理。它说服务器正在发回消息,但我没有收到客户端的任何输入。此外,在服务器发回消息后,应用程序崩溃,表示它正在尝试读取空指针(第 127 行服务器代码)。

需要注意的是,我对这个概念很陌生,而且我并不真正了解选择器。我看过教程,但矛盾的消息让我对这个问题更加困惑。如果有人有关于这个主题的任何好的教程,我将不胜感激。

这是我的代码。

客户主 Activity 屏幕

package com.example.client;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.client.ServerService.Connect;



public class MainActivity extends Activity {

    Button button;
    TextView textView;
    EditText editText;
    EditText editTextps;
    static Handler handler;
    Connect connect=null;
    Object myLock=new Object();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=(Button) findViewById(R.id.button1);
        textView=(TextView) findViewById(R.id.textView1);
        editText=(EditText) findViewById(R.id.editText1);
        editTextps=(EditText) findViewById(R.id.editText2);
        handler=new Handler(){
            @Override
            public void handleMessage(Message msg) { //Handle code for receiving messages 
                super.handleMessage(msg);//when a message is received it's input is processed here
                Bundle bundle=msg.getData();
                if(bundle.getInt("int") == 2){
                    if(bundle.getInt("valid") == 1){
                        Intent i = new Intent();
                        i.setClassName("com.example.client",
                                "com.example.client.ReadyScreen");
                        startActivity(i);
                    }else{
                        alertMessage(); 
                        editText.setText("");
                        editTextps.setText("");
                    }
                }
            }

        };

        startService(new Intent(getBaseContext(), ServerService.class));


        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                String str=editText.getText().toString();
                String strps=editTextps.getText().toString();
                Message msg=Message.obtain();
                Bundle bundle=new Bundle();
                bundle.putString("name", str);
                bundle.putString("password", strps);
                msg.setData(bundle);
                ServerService.threadHandler.sendMessage(msg);
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void alertMessage() {

        final android.app.AlertDialog.Builder show = new AlertDialog.Builder(this).setTitle("Error").setMessage("Wrong username/password").setNeutralButton("close", null);
        show.show();
    }
}

我运行连接和 IO 的服务器服务

package com.example.client;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

public class ServerService extends Service {

    Handler handler;
    static MyHandle threadHandler;
    Connect connect=null;
    Object myLock=new Object();
    static SocketChannel socketChannel=null;
    public ByteBuffer sendBuffer=ByteBuffer.allocate(1024);
    static ByteBuffer receiveBuffer=ByteBuffer.allocate(1024);
    static Selector selector;
    private static final String TAG = ServerService.class.getSimpleName();

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        Log.d(TAG, "Started running the service");
        System.out.println(TAG + "Started running the service");

        (new Thread(new ReceivingThread())).start();
        (new Thread(new SendingThread())).start();

        return START_STICKY;
    }


    @Override 
    public void onDestroy(){
        super.onDestroy();
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();  
    }

    class Connect {
        SocketChannel socketChannel=null;
        public ByteBuffer sendBuffer=ByteBuffer.allocate(1024);
        ByteBuffer receiveBuffer=ByteBuffer.allocate(1024);
        Selector selector;
        public Connect() {

            try {
                socketChannel=SocketChannel.open();
                SocketAddress remoteAddress=new InetSocketAddress("192.168.2.17", 20001);
                socketChannel.connect(remoteAddress);
                socketChannel.configureBlocking(false);
                selector=Selector.open();
                socketChannel.register(selector, SelectionKey.OP_READ);
            } catch (Exception e) {

                e.printStackTrace();
            }
        }
    }

    public class ReceivingThread implements Runnable{

        @Override
        public void run() {
            Log.d(TAG, "Started running the receive thread");
            connect=new Connect();
            try {
                while(true){
                    if(connect.selector.select()==0)
                        continue;
                    Play receivedMessage = new Play();
                    receivedMessage.play();
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }

    }

    public class SendingThread implements Runnable{

        @Override
        public void run() {
            Log.d(TAG, "Started running the send thread");
            Looper.prepare();
            threadHandler=new MyHandle(Looper.myLooper());
            Looper.loop();
        }

    }

    class MyHandle extends Handler{  
        public MyHandle(){
        }
        public MyHandle(Looper looper){ 
                    super(looper);
        }
        public void handleMessage(Message msg){
            String str=msg.getData().getString("name");
            String strps=msg.getData().getString("password");
            MyMessage message=new MyMessage();
            message.setb((byte)1);
            message.setUsername(str);
            message.setPassword(strps);
            try {
                connect.sendBuffer.clear();
                connect.sendBuffer.put(message.Message2Byte());
                connect.sendBuffer.flip();
                connect.socketChannel.write(connect.sendBuffer);
            } catch (Exception e) {

                e.printStackTrace();
            }
        }
    }

}

服务器代码

package mytcp;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

public class NioServer {

    /**
     * @param args
     */
    private int port = 20001;
    final makeFlagFalse timerFlag = new makeFlagFalse();
    static makeFlagFalse loginLoopBoolean = new makeFlagFalse();
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    private static Map<SocketChannel, Integer> clientsMap = new HashMap<SocketChannel, Integer>();
    private Selector selector = null;
    private ServerSocketChannel serverSocketChannel = null;
    private Object gate = new Object();

    public NioServer(int port) {
        this.port = port;
        try {
            init();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException, IOException {
        final NioServer server = new NioServer(20001);
        Thread accept = new Thread() {
            public void run() {
                server.accept();
            }
        };

        accept.start();
        while (loginLoopBoolean.flag == true) 
            server.loginService();
        server.gamePlay(clientsMap);
    }

    public void init() throws IOException {
        selector = Selector.open();
        serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().setReuseAddress(true);
        // serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        System.out.println("服务器启动");
    }

    public void accept() {
        while (true) {
            try {
                SocketChannel socketChannel = serverSocketChannel.accept();
                System.out.println("receive the connection from "
                        + socketChannel.socket().getInetAddress() + ":"
                        + socketChannel.socket().getPort());

                socketChannel.configureBlocking(false);
                synchronized (gate) {
                    selector.wakeup();
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
                System.out.println("Damn it");
            }
        }
    }

    public void loginService() throws InterruptedException {


            synchronized (gate) {
            }
            try {
                int n = selector.select();
                if (n == 0){}
                else{
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey key : selectionKeys) {
                    try {
                        if (key.isReadable()) {
                            handle_receive_login(key);
                        }
                    } catch (Exception e) {
                        try {
                            if (key != null) {
                                key.cancel();
                                key.channel().close();
                            }
                        } catch (Exception ex) {
                            e.printStackTrace();
                        }
                    }
                }
                selectionKeys.clear();
              }
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

    public void handle_receive_login(SelectionKey key) {
        SocketChannel socketChannel = null;
        ServerMessage message = null;
        ServerMessage sendMessage = new ServerMessage();
        socketChannel = (SocketChannel) key.channel();
        rBuffer.clear();
        try {
            int count = socketChannel.read(rBuffer);
            if (count > 0) {
                rBuffer.flip();
                message = ServerMessage.byte2Message(rBuffer.array());
                System.out.println("Receive from"+ socketChannel.socket().getInetAddress() + " : "+ message.getb());
                switch(message.getb()){
                case(1):
                        int valid = DB.idCheck(message.getUsername(),
                                message.getPassword());
                        sendMessage.setb((byte) 2);
                        sendMessage.setValid(valid);
                        sendMes sendMes = new sendMes(sendMessage, socketChannel);
                        sendMes.send();

                    break;
                case(2):
                    break;
                case (3):
                    if(timerFlag.flag){
                        if(message.getReady() == 1){
                            if(clientsMap.size() < 6){
                                clientsMap.put(socketChannel, clientsMap.size() + 1);
                                sendMessage.setb((byte) 3);
                                sendMessage.setReady(1);
                                sendMes sendMes1 = new sendMes(sendMessage, socketChannel);
                                sendMes1.send();
                            }

                            else{
                                sendMessage.setb((byte) 3);
                                sendMessage.setReady(0);
                                sendMes sendMes1 = new sendMes(sendMessage, socketChannel);
                                sendMes1.send();
                            }

                            Timer timer = new Timer();

                            System.out.println("flag is " + timerFlag.flag);
                            TimerTask task = new TimerTask(){
                                public void run(){
                                    timerFlag.falsify();
                                    System.out.println("flag now is " + timerFlag.flag);
                                }
                            };
                            timer.schedule(task, 20*1000);
                        }
                    }else{
                        sendMessage.setb((byte) -1); /*-1 implies that game is currently in progress*/
                        sendMes sendMes1 = new sendMes(sendMessage, socketChannel);
                        sendMes1.send();
                    }
                    break;

                case (4):
                    if(timerFlag.flag == true){
                        sendMessage.setb((byte) -2); /*send message saying "waiting for other players*/
                        sendMes sendMes1 = new sendMes(sendMessage, socketChannel);
                        sendMes1.send();
                    }else{
                        loginLoopBoolean.falsify();
                    }
                    break;
                }   
            }/*end of if(count=0)*/
        } catch (Exception e) {
            e.printStackTrace();
            key.cancel();
            try {
                socketChannel.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    }


    public void gamePlay(Map<SocketChannel, Integer> clientsMap) throws IOException, InterruptedException{
        Dealer dealer = new Dealer();
        dealer.createDeck();
        ServerMessage sendMessage = new ServerMessage();

        if(!clientsMap.isEmpty()){  
            Set<SocketChannel> clientSet = clientsMap.keySet();
            Iterator<SocketChannel> iterator=clientSet.iterator();
            SocketChannel currentPlayer;
            while(iterator.hasNext()){
                currentPlayer=iterator.next();  
                sendMessage.setb((byte) 4);
                sendMessage.setCard1(dealer.dealCard(dealer.deck));
                sendMessage.setCard2(dealer.dealCard(dealer.deck));
                sendMes sendMes1 = new sendMes(sendMessage, currentPlayer);
                sendMes1.send();
            }
            //send who's turn it is 
            loginService();
        }
    }

    public static class makeFlagFalse{
        boolean flag;
        public makeFlagFalse() {
            this.flag = true;
        }
        public void falsify(){
            flag = false;
        }
        public void makeTrue(){
            flag = true;
        }
    }

    public class sendMes{
        ServerMessage message;
        SocketChannel currentPlayer;

        sendMes(ServerMessage message,SocketChannel currentPlayer){
            this.message = message;
            this.currentPlayer=currentPlayer;
        }
        public void send() throws IOException{
            sBuffer.clear();
            sBuffer.put(message.Message2Byte());
            sBuffer.flip();
            currentPlayer.write(sBuffer);
        }
    }


}

我很感激任何形式的帮助。

谢谢

最佳答案

private Object gate = new Object(); 

它应该是不稳定的

关于java - Android NIO 服务器选择器在没有消息发送时读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17853017/

相关文章:

android - 单选按钮对齐

安卓用户界面 : TransitionDrawable

c# - C# 中是否有众所周知的异步网络代码模式?

php - 通过套接字从 PHP 向 Python 发送消息

node.js - 在 heroku 上部署 node.js TCP 服务器

java - Checkstyle 未检测到 @throws 标记

java - 在处理程序使用 Netty 接收事件之前,如何将对象附加到 channel ?

java - Textview文字大小应为editText文字大小并显示在listview中

java - 如何读出文本文件

Android静音/取消静音手机