繁体   English   中英

套接字连接时CPU使用率过高

[英]Excessive CPU usage upon socket connection

我有一个客户端类,它允许我连接到ntrip客户端服务(它基本上是一个http服务)。 此客户端允许我连接到安全和不安全的服务。 我正在使用javax.net库。 这是我的代码:

public class ntripClient_mng implements Runnable{
private static String nServer = "";
private static String nMountpoint = "";
private static String nUsername = "";
private static String nPassword = "";
private static int nPort = 0;
private boolean running = true;
private static boolean secure = false;

public static void main(String[] args){
    for (int i = 0; i < args.length; i++){
        if (args[i].equals("-a")){nServer = args[i+1];}
        if (args[i].equals("-p")){nPort = Integer.parseInt(args[i+1]);}
        if (args[i].equals("-u")){nUsername = args[i+1];}
        if (args[i].equals("-pw")){nPassword = args[i+1];}
        if (args[i].equals("-m")){nMountpoint = args[i+1];}
        if (args[i].equals("-s")){secure = args[i+1].matches("Y") ? true : false;}
    }

public ntripClient_mng(String server, int port, String user, String pass, String mount, String cType){
    nServer = server;
    nUsername = user;
    nPassword = pass;
    nMountpoint = mount;
    nPort = port;
    secure = cType.matches("Y") ? true : false;
}

@Override
public void run() {
    DataOutputStream out = null;
    DataInputStream in = null;
    try {
        Socket s = null;
        SSLSocket sslSocket = null;
        // Creating Client Sockets
        if (secure){
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
            sslSocket = (SSLSocket)sslsocketfactory.createSocket(nServer,nPort);
        } else {
            SocketAddress sockaddr = new InetSocketAddress(nServer, nPort);
            s = new Socket();
            s.connect(sockaddr, 10 * 1000);
        }
        if (true) {
            if (secure){
                sslSocket.setSoTimeout(15000);
                out = new DataOutputStream (sslSocket.getOutputStream());
                in = new DataInputStream (sslSocket.getInputStream());
            } else {
                s.setSoTimeout(15000);
                out = new DataOutputStream (s.getOutputStream());
                in = new DataInputStream (s.getInputStream());
            }

            // send a message to the server
            String requestmsg = GETrequest();
            out.write(requestmsg.getBytes());
            out.flush();
            while (running) {
                // receive a response
                byte[] b = new byte[1];
                if (first){
                  for (;;){
                    in.read(b);
                    if (b[0] == -45) break;
                  }
                  baos.write(b);
                  first = false;
                }
                for (;;){
                   in.read(b);
                   if (b[0] == -45){
                      break;
                   } else {
                      baos.write(b);
                   }
                }
                byte[] bytes = baos.toByteArray();
                decodeMessage(bytes);
                baos.reset();
                baos.write(b);
            }
        }
    } 
    catch (UnknownHostException ex) {ex.printStackTrace();} 
    catch (IOException ex) {ex.printStackTrace();} 
}}

该代码对于安全连接和非安全连接均能正常工作。 但是,困扰我的是连接到不安全的服务时CPU使用率过高。 当我连接到安全服务时,一个正在运行的线程的CPU使用率约为0.3%。 当我连接到不安全的服务器时,CPU使用率约为30%。 显然这里有一个问题,但我不明白它是什么。

编辑

我已经根据答案中的建议编辑了代码。 现在我正在读取数据,一次读取一个字节,并使用一个停止字节来停止读取。 这可能是正确的方法,但问题仍然存在。 连接到某些服务时,CUP使用率达到30%。

可能是什么问题? javax.net库是否有问题? 问题可能是由服务器本身引起的吗? 任何帮助,将不胜感激。

// send a message to the server
while (running)
{
    // receive a response
    if (secure)
    {
      // ... some code here
    }
    else
    {
      // !CHANGES HERE!
      byte[] bytes = readTillTimeout(in);
      decodeMessage(bytes);
    }
}

我通常只读取每个字节,然后使用ByteArrayOutputStream将它们加在一起。

如果没有更多的可用字节,则read方法将锁定一小段时间(您指定的setSoTimeout(...) )。 如果在该延迟内什么都没收到,则它将抛出SocketTimeoutException ,这意味着数据已到达末尾。

private byte[] readTillTimeout(DataInputStream in) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
    try
    {
        int input = in.read();
        if (input == -1) throw new IllegalStateException("disconnected");
        baos.write((byte)input);
    }
    catch (SocketTimeoutException ste)
    {
    }
    return baos.toByteArray();
}

我认为setSoTimeout(value)不应超过2秒。

我在许多应用程序中都使用了这种方法。 我只是用您指定的代码对此进行了测试。 就像您说的那样,在CPU使用率达到30%之前。 现在大约是0%。

编辑:(因为EJP拒绝了我的回答)

今天我们的听众很困难。

是的,的确超时并不总是一个好的解决方案。 有时您想阅读直到找到特定字符为止。 与工业机器通信的一种非常流行的方法是使每个消息STX (0x02)字节开头,并使其以ETX (0x03)字节结尾。

这是一个使用startBytestopByte输入的代码示例。

private byte[] readMessage(DataInputStream in, byte startByte, byte stopByte) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
    try
    {
        for(;;)
        {
            int input = in.read();
            if (input == -1) throw new IllegalStateException("disconnected");
            if (input == startByte) break;
        }

        for(;;)
        {
            int input = in.read();
            if (input == -1) throw new IllegalStateException("disconnected");
            if (input == stopByte) break;
            baos.write((byte)input);
        }
    }
    catch (SocketTimeoutException ste)
    {
      return null;
    }
    return baos.toByteArray();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM