设置套接字客户端始终监听数据

时间:2015-07-21 03:06:45

标签: java android sockets serversocket

我可以设置客户端Socket向服务器发送请求(sendData()方法)并正确读取收到的消息(readData()方法),但每次发送时我都只收到消息通过以下代码使用MOBILE_REQUEST字符串对服务器的请求:

@Override
protected Boolean doInBackground(String... params) {
    try {
        mSocket = new Socket(
                // PC Ip is 192.168.1.199 
                // It is the other device, Not be local host : 127.0.0.1
                Pas.pas.getPcIP(), 17001);

        DataOutputStream mDos = new DataOutputStream(mSocket.getOutputStream());

        String RESPONSE = null;
        String MOBILE_BLOCK = "MobileBlock#";

         // Converting collected data in byte array into String.
         RESPONSE = sendData(mDos, MOBILE_BLOCK);

         /**
           * The result response from PC app in here
           */
         // Log : response - #WindowsResp#192.168.1.199#
         Log.i("", "response '" + RESPONSE + "'");

        }

    } catch (SocketTimeoutException e) {
        IS_SOCKET_TIME_OUT = true;

        e.printStackTrace();
    } catch (ConnectException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

sendData()方法 - 客户端将请求发送到服务器并等待获取响应数据 - 字符串数据。

private String sendData(DataOutputStream mDos, String MOBILE_REQUEST) {
    try {
        // Log : MOBILE_REQUEST.getBytes() - [B@82f10f8
        mDos.write(MOBILE_REQUEST.getBytes());

        // todo I should set this sleep, bcs TCP has delay time, 
        // so i need set the delay time for client should receive data
        // otherwise, sometimes I did not receive anything
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Log : #WindowsResp#192.168.1.199#
        return new String(readData(mSocket));
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

readData()方法 - 从服务器收到数据后读取数据。

public static byte[] readData(Socket mSocket) {
    /* Since data are accepted as byte, all of them will be collected in the
        following byte array which initialised with accepted data length. */
    DataInputStream mDis = null;
    try {
        mDis = new DataInputStream(mSocket.getInputStream());

        // Log : mDis.available() - 23
        byte[] data = new byte[mDis.available()];

        // Collecting data into byte array
        for (int i = 0; i < data.length; i++)
            data[i] = mDis.readByte();

        // Log : data - [B@30c044a4
        return data;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

我想要的是每次服务器通过单击按钮向我的套接字客户端发送消息时,套接字客户端应该接收它。但是在上面的代码中,它不是。

请帮我看看如何设置套接字客户端始终从服务器监听?

p / s:或者我需要设置ServerSocket吗?如果使用ServerSocket我不能使用相同的端口,对吧?因为当我首先打开ServerSocket进行侦听时(例如,在端口17001),我无法使用客户端套接字通过端口17001发送请求,因为该端口已被使用。

已更新

服务器(PC应用程序 - 笔记本电脑设备)发送到客户端(移动设备 - Android)的方式是通过Socket TCP,通过以下步骤:

1 - 客户端(Android设备)设置与服务器(PC应用程序)的TCP套接字连接(此连接永远不会关闭,直到以onDestroy()方法退出应用程序。)

2 - 客户端向服务器发送请求,例如MOBILE_REQUEST = "MobileID#MobileIP#"

3 - 服务器收到客户端的请求,它通过Socket连接回复客户端,实际上客户端正确接收了数据。恩。 "WindowsRep#WindowsIP"

这种方式对我不起作用,即使套接字TCP连接未关闭,getInputStream()也没有关闭。在这种情况下:

服务器通过Socket连接向客户端发送字符串数据,客户端正确接收数据。

我想要的是每次“服务器通过Socket连接向客户端发送字符串数据,客户端正确接收数据”。但就我而言,客户端只在向服务器发送请求后才接收数据。

C#服务器

服务器套接字

IPEndPoint ipe = new IPEndPoint("192.168.1.199", 17001);
svSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
svSocket.Bind(ipe);

服务器发送数据

string data_send = "#WBroad#" + "192.168.1.199" + "#";
byte[] byteData = Encoding.UTF8.GetBytes(data_send);
c.ClientSocket.Send(byteData);

1 个答案:

答案 0 :(得分:0)

由于您尚未发布发送代码,因此无法确定您为什么不接收数据,但这里是对您发布的内容的快速批评:

 //            mSocket.setReuseAddress(true);

你已经将其解决了,但现在调用这种方法毫无意义。您必须将套接字构造为new Socket(),不带参数,然后调用此方法,然后调用connect()。由于您没有提供要重复使用的源端口或IP地址,因此它仍然毫无意义。

        byte[] data = new byte[mDis.available()];

这是对available()的完全滥用。它不提供消息长度。见Javadoc。没有理由相信此时已经到达的任何数据,如果有的话,是完整的消息,或者只有一条消息。如果你想要消息,你不会从TCP获得任何帮助:你必须自己实现它们。由于您的协议似乎是基于文本的,因此我建议您使用行readLine()BufferedReaderBufferedWriter而不是DataInput/OutputStreams。并且在套接字的生命周期中构建一次,而不是每个应用程序消息构建一次,否则您将丢失数据。

        // Collecting data into byte array
        for (int i = 0; i < data.length; i++)
            data[i] = mDis.readByte();

巨大的问题是它不会阻止,因为大多数情况下,available()将为零,所以这个方法除了返回之外什么也不做空byte[]数组。

在任何情况下,这完全相当于mDis.readFully(data);,只有效率低几倍,但你不应该这样做:见上文。

    return data;    
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;

这是不好的做法。你应该让这个方法抛出IOException并让调用者处理它。

        mDos.write(MOBILE_REQUEST.getBytes());

见上文。这应包括行终止符,长度字前缀或其他一些分隔消息的方式。

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

这种睡眠实际上完全是浪费时间。和空间。去掉它。睡在网络代码中只是货物编程。

        return new String(readData(mSocket));

如果NullPointerException返回readData(),则会null抛出IOException,如果有private boolean splitData(int mobile_send_request_case, String DATA) { ,则返回ServerSocket,这是让该方法传播该异常的另一个原因在内部捕获并返回null。

ServerSocket

此方法与问题完全无关,不应发布。

  

或者我是否需要设置ServerSocket

没有。你为什么这么想?

  

如果使用PizzaPlanetApp我不能使用相同的端口,对吧?

错误。

  

因为当我首先打开var app = angular.module("PizzaPlanetApp", []); 进行侦听时(例如,在端口17001),我无法使用客户端套接字通过端口17001发送请求,因为该端口已被使用。

再次错了。它不是。

正如我上面所说的那样,当你没有发布所有相关代码时,你无法进一步帮助你,但是你已经有足够的错误了,你真的需要重新开始。