在Android客户端中连接tcp有点麻烦

时间:2012-07-11 01:29:51

标签: android login tcp client

这可能是我的应用程序的一个复杂问题,但我会尽我所能准确地描述它。

我正在制作一个Android客户端,并利用其他人在工作时交给我的一些帮助程序。辅助Android类称为TcpClient.java和PVDCAndroidClient.java。 PVDCAndroidClient.java使用TcpCLient,使用tcpCLient对象通过serverIP和端口连接。

这是PVDCAndroidClient.java:

    public class PVDCAndroidClient {

    // constants
    public static final String DEFAULT_LOGIN_URI = "http://me.net:8000/";


    private TcpClient tcpClient = null;
    private UdpClient udpClient = null;
    private boolean connected = false;
    private boolean loggedin = false;
    private static SimpleDateFormat sdf;
    private String loginURI = DEFAULT_LOGIN_URI;
    private int getUserNumber;
    TcpMessageListener listener = null;

    /**
     * Connects to proxy server, blocks until complete or timeout
     * @param serverIP
     * @param port
     */
    public void connect(String serverIP, int port)
    {
        try
          {
            if(serverIP.length() != 0 && port != 0)
            {
              tcpClient = new TcpClient();

              tcpClient.addTcpListener(listener);
              tcpClient.connect(serverIP, port);

            }
          }
        catch(Exception e)
        {
            e.printStackTrace();
            Log.d("Could not connect to server, possbile timeout...", "error");
        }



    }

    ///// Make login function a blocking call

    // Default login, use last location as login location
    public boolean login(String fName, String lName, String password)
    {
        return this.login(fName, lName, password, "last location");
    }

    public boolean login(String fName, String lName, String password, String region)
    {
        return this.login(fName, lName, password, "last location", 128, 128, 20);
    }

    public boolean login(String fName, String lName, String password, String region, int loginX, int loginY, int loginZ)
    {            sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
                 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

        // Check passed values
            // x, y and z should be between [0, 256]
            // strings should not be null or empty(except lName which can be empty)
        if((loginX >= 0 && loginX <= 256) && (loginY >=0 && loginY <= 256) && (loginZ >= 0 && loginZ <= 256))
        {
            if(fName.length() != 0 && fName != null)
            {


                // Construct packet xml structure

                // Send request and wait until reply or timeout

                // return false if timeout (or throw exception?)
                // if not timeout, read result packet and determine return value

                // getUserNumber = tcpClient.getUserNum();

                StringWriter stringWriter = new StringWriter();


                XmlSerializer serializer = Xml.newSerializer();

                try {

                    serializer.setOutput(stringWriter);

                    // Indentation is not required, but helps with reading
                    serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

                    // TODO: Remove hardcoding of strings, make either constants or place in strings.xml
                    // TODO: Move the header construction to other method as it is fairly constant other than request num and no need to repeat that much code
                    serializer.startTag("", "pvdc_pkt");

                        serializer.startTag("", "pvdc_header");




                            // TODO: replace this with a string unique to the system
                            serializer.startTag("", "ID");
                                serializer.text("838393djdjdjd");
                            serializer.endTag("", "ID");

                            // TODO: replace this with actual user number from server
                            serializer.startTag("", "user_num");
                                serializer.text("22");//get userNum from above
                            serializer.endTag("", "user_num");

                            // TODO: add a request number counter to increment this on each request
                            serializer.startTag("", "request_num");
                                serializer.text("1");
                            serializer.endTag("", "request_num");

                            serializer.startTag("", "DateTime");
                                serializer.text(sdf.toString()); //utc time variable.
                            serializer.endTag("", "DateTime");

                        serializer.endTag("", "pvdc_header");

                        serializer.startTag("", "pvdc_content");
                            serializer.attribute("", "type", "requestlogin");

                            serializer.startTag("", "name");
                                serializer.attribute("", "fname", fName);
                                serializer.attribute("", "lname", lName);
                            serializer.endTag("", "name");

                            serializer.startTag("", "password");
                                serializer.text(password);
                            serializer.endTag("", "password");

                            serializer.startTag("", "server");
                                serializer.text(this.loginURI);
                            serializer.endTag("", "server");

                            serializer.startTag("", "location");
                                serializer.attribute("", "region", region);
                                serializer.text(loginX + ";" + loginY +";" + loginZ);
                            serializer.endTag("", "location");

                        serializer.endTag("", "pvdc_content");

                    serializer.endTag("", "pvdc_pkt");

                    // Finish writing
                    serializer.endDocument();
                    // write xml data out
                    serializer.flush();

                    // 
                    sendLogin(stringWriter);

                } catch (Exception e) {
                    Log.e("Exception", "error occurred while creating xml file");
                    return false;
                }
                // Print out xml for debugging
                Log.d("PVDCAndroidClient Login", stringWriter.toString().trim());

            }
            else
            {
                Log.d("Error in name checking", "fName either blank or null");
            }

         }
        else
        {
            Log.d("login coordinates X,Y, or Z not between 0-256", "Coordinates Error");
        }

        return true;
       }


    // moveString should contain the properly formatted movement command(s)[see above move request description]
    public void sendLogin(StringWriter stringWriter)
    {
        tcpClient.sendMessage(stringWriter.toString());
    }
}

这是实际的TcpClient.java:

    public class TcpClient {

    public interface TcpMessageListener{

        public void onMessage(TcpClient client, String message);
    }

    private Socket socket = null;
    private PrintWriter out = null;
    private BufferedReader in = null;
    private Thread listenThread = null;
    private boolean listening = false;
    private int userNum = -1;
    private List<TcpMessageListener> listeners = new ArrayList<TcpMessageListener>();


    public int getUserNum()
    {
        return this.userNum;
    }

    public TcpClient() {

    }

    public void addTcpListener(TcpMessageListener listener)
    {
        synchronized(this.listeners)
        {
            this.listeners.add(listener);
        }
    }

    public void removeTcpListener(TcpMessageListener listener)
    {
        synchronized(this.listeners)
        {
            this.listeners.remove(listener);
        }
    }

    public boolean connect(String serverIpOrHost, int port) {
        try {
            socket = new Socket(serverIpOrHost, port);
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.listenThread = new Thread(new Runnable(){

                public void run() {
                    int charsRead = 0;
                    char[] buff = new char[4096];
                    while(listening && charsRead >= 0)
                    {
                        try {
                            charsRead = in.read(buff);
                            if(charsRead > 0)
                            {
                                Log.d("TCPClient",new String(buff).trim());
                                String input = new String(buff).trim();
                                synchronized(listeners)
                                {
                                    for(TcpMessageListener l : listeners){
                                        l.onMessage(TcpClient.this, input);
                                    }
                                }

                                if (input.toLowerCase().contains("<user_num>")){
                                    int index = input.toLowerCase().indexOf("<user_num>");
                                    index += "<user_num>".length();
                                    int index2 = input.toLowerCase().indexOf("</user_num>");
                                    userNum = Integer.parseInt(input.substring(index,  index2));

                                }
                            }
                        } catch (IOException e) {
                            Log.e("TCPClient", "IOException while reading input stream");
                            listening = false;
                        }
                    }
                }

            });

            this.listening = true;
            this.listenThread.setDaemon(true);
            this.listenThread.start();

        } catch (UnknownHostException e) {
            System.err.println("Don't know about host");
            return false;
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection");
            return false;
        } catch (Exception e) {
            System.err.println(e.getMessage().toString());
            return false;
        }
        return true;
    }

    public void sendMessage(String msg) {
        if(out != null)
        {
            out.println(msg);
            out.flush();
        }
    }

    public void disconnect() {
        try {
            if(out != null){
                out.close();
                out = null;
            }
            if(in != null){
                in.close();
                in = null;
            }
            if (socket != null) {
                socket.close();
                socket = null;
            }
            if(this.listenThread != null){
                this.listening = false;
                this.listenThread.interrupt();
            }
            this.userNum = -1;
        } catch (IOException ioe) {
            System.err.println("I/O error in closing connection.");
        }
    }
}

最后,这是我今天编写的内容,似乎无法使其工作。我没有得到任何明显的例外,只是对Logcat发出警告,说“无法获得连接的I / O”。

    public class AndroidClientCompnt extends Activity {

    private TcpClient myTcpClient = null;
    private UdpClient udpClient;
    private static final String IP_ADDRESS_SHARED_PREFS = "ipAddressPref";
    private static final String PORT_SHARED_PREFS = "portNumberPref";
    private String encryptPassLoginActivity;
    private String getIpAddressSharedPrefs;
    private String getPassword, getName, getRegionSelect, getGridSelect;
    private String fName, lName;
    private SharedPreferences settings;
    private boolean resultCheck = false;
    private int portNum;
    PVDCAndroidClient client;
    private String name;
    private CharSequence[] getView;

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

        Intent intent = getIntent();
        // getting object's properties from LoginActivity class.

        getName = intent.getStringExtra("name");
        getPassword = intent.getStringExtra("password");
        getRegionSelect = intent.getStringExtra("regionSelect");
        getGridSelect = intent.getStringExtra("gridSelect");

        Log.d("VARIABLES", "getName = " + getName + "getPassword" + getPassword
                + "getRegionSelect = " + getRegionSelect + ".");
        setResult(Activity.RESULT_CANCELED);

        client = new PVDCAndroidClient();
    }

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

        // Take care of getting user's login information:

        // grid selected as well? sometime?

        settings = PreferenceManager.getDefaultSharedPreferences(this);

        getIpAddressSharedPrefs = settings.getString(IP_ADDRESS_SHARED_PREFS,
                "");
        portNum = Integer.parseInt(settings.getString(PORT_SHARED_PREFS, ""));
        Log.d("SHARED" + getIpAddressSharedPrefs + "port " + portNum, "");

        if (getIpAddressSharedPrefs.length() != 0 && portNum != 0) {

            try {
                // first connect attempt.

                client.connect(getIpAddressSharedPrefs, portNum);
                resultCheck = client.isConnected();

                // here is where I want to call Async to do login
                // or do whatever else.

                UploadTask task = new UploadTask();
                task.execute();

            } catch (Exception e) {
                Toast.makeText(getApplicationContext(), "Could not connect.",
                        Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }

        } else {
            Toast.makeText(getApplicationContext(),
                    "Ip preference and port blank", Toast.LENGTH_LONG).show();
        }

        finish();
    }

    private class UploadTask extends AsyncTask<String, Integer, Void> {
        @Override
        protected void onPreExecute() {
            Toast.makeText(getApplicationContext(), "Loading...",
                    Toast.LENGTH_LONG).show();
        }

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

            // encrypting user's password with Md5Hash class.
            try {
                encryptPassLoginActivity = MdHashing
                        .MD5(getPassword.toString());
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            if (resultCheck == true) {

                String[] firstAndLast;

                String spcDelmt = " ";

                firstAndLast = name.toString().split(spcDelmt);

                fName = firstAndLast[0];
                lName = firstAndLast[1];

                // set up the tcp client to sent the information to the
                // server.
                client.login(fName, lName, encryptPassLoginActivity,
                        getRegionSelect, 128, 128, 20);

            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {

            Intent goToInWorld = new Intent(
                    AndroidClientCompnt.this.getApplicationContext(),
                    PocketVDCActivity.class);
            startActivity(goToInWorld);
            Toast.makeText(getApplicationContext(), "Connected",
                    Toast.LENGTH_LONG).show();

        }

    }

}

我知道这是一篇超级长篇文章而且我要求很多,但如果有人能看一眼,我会非常感激。我整天都在这里,试图利用我得到的这些辅助课程,无法让它工作。我对这个客户端/服务器的东西也没有太多经验也没有帮助。正确方向的任何推动或接受的解决方案对我来说真的意味着什么。

谢天谢地,

祝你晚安。

2 个答案:

答案 0 :(得分:1)

你可以发布你的清单吗?

您可能需要添加以下内容:

 <uses-permission android:name="android.permission.INTERNET"/>

此外 - 我假设您在此连接的服务器端看不到任何事情?

答案 1 :(得分:0)

1)确保您在Android-Manifest文件中拥有以下权限:

 <uses-permission android:name="android.permission.INTERNET/> 

没有这个你肯定不会进行任何tcp / ip连接。

2)您需要在调试模式下运行代码,并将断点放在连接信息的位置    已设置,以及在几个点上的结果。换句话说,你需要深入挖掘。

如果您对编码有点新意,那么没有比运行调试器和逐行执行代码更好的时间投入。代码仅在调试器中生效,您可以在其中查看变量和结果的值。所以设置几个断点,一步一步,你会看到更多。然而,在有线程的地方调试更加困难。