从JAVA中的服务器套接字缓冲区接收时消除半字符串

时间:2017-08-03 12:43:45

标签: java sockets buffer nio

我在一个程序中编写了一个简单的NIO服务器和内部客户端(在同一程序中),以便服务器从外部接收数据,而内部客户端将服务器接收的数据发送到服务器外部。我使用While()循环在两个并行线程中连续运行这两个进程。现在问题是,我将以非常高的速度向Inside服务器和我收到的所有内容接收数据,我将使用Inside客户端将它们发送到外部服务器。有时,从Buffer中检索数据导致总字符串的一半大小。这意味着我收到“HELLO”,但总字符串是“HELLO SERVER”。这只是一个例子。我会收到很长的字符串。类似地,在通过内部客户端将数据发送到外部服务器之后,我将监听数据并且我正在接收相同的半字符串。我有什么方法可以消除这些半字符串并获得全长字符串。我必须毫不失败地获得完整的字符串。

我正在为进程使用while循环。这使得CPU利用率高达50%。有没有什么办法可以在不使用Thread.sleep方法的情况下降低CPU利用率?因为我需要不断收听外方的数据。他们可能会为一个请求发送2-4个字符串。我尝试使用Executor服务线程连续运行进程,但它需要包含一些睡眠。如果我包含一些睡眠,我无法获得字符串,如果我不包括睡眠,我的CPU利用率将非常高(50-60%)。有谁可以帮我解决这两个问题?

这是我的代码:

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_my_books, container, false);

    final ListView booksIdListView = (ListView) view.findViewById(R.id.booksIdListView);

    FirebaseDatabase database = FirebaseDatabase.getInstance();
    DatabaseReference databaseReference = database.getReference();

    final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
    String UID = user.getUid();

    databaseReference.child("books").child(UID).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            final List<String> booksId = new ArrayList<String>();

            for (DataSnapshot child:  dataSnapshot.getChildren()) {
                String userBookId = child.getKey();

                booksId.add(userBookId);
            }

            ArrayAdapter<String> myBooksAdapter = new ArrayAdapter<String>(getActivity() ,
  android.R.layout.simple_list_item_1 , booksId);
            booksIdListView.setAdapter(myBooksAdapter);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

1 个答案:

答案 0 :(得分:1)

让我们假设您的服务器在每个字符串后附加消息结束标记字符串,例如"<EOM>",然后对代码进行以下修改(将其视为草图,因为我没有完全验证它)可以用来等待完整的字符串:

String end = "<EOM>";
StringBuilder curStr = new StringBuilder();

int numRead = 0;
while(-1 != (numRead = channel.read(buffer))){
  curStr.append(new String(buffer.array(), 0, numRead, Charset.forName("UTF-8")));
  int endIdx = curStr.indexOf(end);
  if (endIdx != -1) {
    fromOMSqueue.add(curStr.substring(0, endIdx + end.length()));
    break;
  }
}

if (numRead == -1) {
  Socket socket = channel.socket();
  SocketAddress remoteAddr = socket.getRemoteSocketAddress();
  System.out.println("Connection closed by client: " + remoteAddr);
  channel.close();
  return;
}

String msg = fromOMSqueue.poll();