1

第一:我希望我的英语不是那么差(也许是格格利语;德语语法和英语词汇)

我正在为android编写一个java服务器,它与在WindowsCE 5上运行的用c#编写的客户端通信。最大的问题是,有时特别是或者可能只有在网络不稳定时,我的java服务器仍然阻塞在accept-Method中客户端正在发送数据。我通过关闭和打开两个设备通信的虚拟路由器来模拟不稳定的网络。我还可以识别出 c# 程序在写入或读取方法中挂起,或者在网络打开并且我的服务器正在侦听预期端口时引发 IOException。

这是客户端的源代码:

一些信息:1.发送10000条消息仅用于测试

static void Main(string[] args)
{
    string server = ...;
    int port = 12000;
    String outputStr = "";
    NetworkStream stream = null;
    for (int i = 0; i < 10000; i++)
    {
        TcpClient client = null;
        String messageToSend = ...
        try
        {
            IPAddress ipAddress = IPAddress.Parse(server);
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port);
            AutoResetEvent connectDone = new AutoResetEvent(false);
            client = new TcpClient();
            client.Client.BeginConnect(ipEndPoint,
                new AsyncCallback(
                        delegate(IAsyncResult ar)
                        {
                            try
                            {
                                client.Client.EndConnect(ar);
                                connectDone.Set();
                            }
                            catch (Exception ex)
                            {}
                        }
                    ), client.Client);

                if (!connectDone.WaitOne(5000, false))
                {
                    outputStr = "NOTConnected";
                }
                Byte[] data = System.Text.Encoding.UTF8.GetBytes(messageToSend);
                stream = client.GetStream();
                try
                {
                    stream.Write(data, 0, data.Length);
                    data = new Byte[2048];
                    int bytes = stream.Read(data, 0, data.Length);
                    string responseData = System.Text.Encoding.UTF8.GetString(data, 0, bytes);
                    outputStr = responseData;
                }
                catch (IOException ex)
                {
                    outputStr = ex.Message;
                }
            }
        }
        catch (SocketException ex)
        {
            outputStr = ex.Message;
        }     
        catch (Exception ex)
        {
            outputStr = ex.Message;
        }
        finally
        {
            if (stream != null) stream.Close();
        }
        System.Threading.Thread.Sleep(200);
    }
    Console.WriteLine("\n Press Enter to continue... " + outputStr);
    Console.Read();
}

我的服务器源代码:

一些信息。我的 servlet 通常是一个内部类,首先检查设备是否连接到路由器。如果是它开始到这里的一个端口。如果不是,它会进入等待模式(参见 _sendToSleep())。如果设备重新连接,则活动可以通过通知将其唤醒。如果它再次失去连接,Activity 将通过关闭套接字导致 SocketException,以便 servlet 可以离开接受方法。

public class ServletThread extends Thread {

    private int port;
    private ServerSocket serverSocket;
    private Socket socket;

    public ServletThread(int port) throws IOException {
        super();
        this.port = port;
        serverSocket = new ServerSocket(port);
    }

    private void checkConnectivity(BufferedWriter out) {
        try {
            String outgoingMsg = "connected";
            out.write(outgoingMsg);
            out.flush();
        } catch (IOException e) {
            Log.e(TAG, "connectivity exception " + e.getMessage());
        }
    }

    private void readStream(Scanner scanner) throws IOException {
        String str = "";
        while (scanner.hasNext()) {
            str += scanner.nextLine();
        }
        final String fTicket = str;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (MyActivity.this.isFinishing()) {
                    return;
                }
                // do something
            }
        });
    }

    private void _sendToSleep() {       
        try {
            synchronized (this) {
                this.wait();
            }
        } catch (InterruptedException e) {
            this.interrupt();
        }
    }

    @Override
    public void interrupt() {
        super.interrupt();
        if (serverSocket != null) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                Log.e(TAG, ""+e.getMessage());
            }
        }
    }

    @Override
    public void run() {
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException ex) {
            Log.e(TAG,""+ex.getMessage());
        }
        while (!isInterrupted()) {
            if (connectionState != NetworkInfo.State.CONNECTED) {
                _sendToSleep();
            } else {
                BufferedWriter out = null;
                Scanner scanner = null;
                try {
                    socket = serverSocket.accept();
                    out = new BufferedWriter(new OutputStreamWriter(
                                socket.getOutputStream()));
                    scanner = new Scanner(socket.getInputStream());
                    checkConnectivity(out);
                    readStream(scanner);
                } catch (IOException ex) {
                    Log.e(TAG, ex.getMessage() + "");
                } finally {
                    if (socket != null) {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            Log.e(TAG, "exception on close socket " + e.getMessage());
                        }
                    }
                    if (scanner != null) {
                        scanner.close();
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            Log.e(TAG, ""+e.getMessage());
                        }
                    }
                }
            }
        }
    }
}

隔离错误后,我做了一些更改:

c#而不是stream = client.getStream

(using Stream = client.getStream()) {
    ...
    stream.WriteTimeout = 1000;
    stream.ReadTimeout = 1000;
    ...
}

在 _sendToSleep() 中的 java 更改

private void _sendToSleep() {
    if (serverSocket != null) {
        try {
            serverSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "failed to close serverSocket " + e.getMessage());
        }
    }
    try {
        synchronized (this) {
            this.wait();
        }
    } catch (InterruptedException e) {
        this.interrupt();
    }
    try {
        serverSocket = new ServerSocket(port);
    } catch (IOException e) {
        Log.e(TAG, "failed to open serversocket " + e.getMessage());
    }
}

它变得更好,意味着我无法重现该问题。

我的问题:

为什么客户端挂了?(可能是socketserver和wlan-adapter在重新连接几次后servlet端和客户端的同步问题,导致servlet无法获取任何数据???)我的更改是否解决了这个问题。

感谢你在期待!

4

0 回答 0