【问题标题】:Java server socket sending multiple messages issueJava服务器套接字发送多条消息问题
【发布时间】:2013-02-02 15:22:54
【问题描述】:

我们有一个 java 套接字程序,服务器从许多设备获取数据并且工作正常。有时服务器需要向设备发送一些命令。当它发送单个命令时,它工作正常。当它发送多个命令时,问题就来了,只有第一个是成功的。我们无法弄清楚为什么其余的都失败了。下面是显示消息如何发送的 sn-p。我应该在消息发送后设置延迟吗?

public static void main(String[] args) {   

      new sServer7888();

   }
sServer7888() {


    try{
    final ServerSocket serverSocketConn = new ServerSocket(7888);               
    while (true){
    try{
       Socket socketConn1 = serverSocketConn.accept();
          new Thread(new ConnectionHandler(socketConn1)).start();                       
    }
    catch(Exception e){
        e.printStackTrace(System.out);
    }
       }
    } 
    catch (Exception e)     {
         e.printStackTrace(System.out);
    }

}


class ConnectionHandler implements Runnable {

  private Socket receivedSocketConn1;
    ConnectionHandler(Socket receivedSocketConn1) {
      this.receivedSocketConn1=receivedSocketConn1;
    }

    public void run() {

      while ((nextChar=readIn1.read()) != -1) {

         completeMessage += (char) nextChar;     
         if (nextChar == '*')
    {
         String[] splitResult = completeMessage .split(",");    
         String header=splitResult[0].trim().substring(0,4);

         if((header.equals("$ACK")){

          //update the message sent from the server as already acknowledge.
         }     
         else{
          //run query to find if there are any message to be sent out to the devices
          while(rsOC1.next()){
            commandText = rsOC1.getString("commandText");
            writeOut1.write(commandText);
            writeOut1.write("\r\n");
            writeOut1.flush(); 
          }

          //now process the normal message receive from the devices.
         } 
        completeMessage="";
       }   
      }
   }
}

【问题讨论】:

  • 您是否检查过rs0c1.next() 在第一次迭代后是否返回true?
  • @VishalK 是的,我已经检查过它是否工作正常,因为我收到了很多这样的消息。
  • 如果把客户端接收消息的代码放在这里就好了...
  • 您是否尝试过查看 writeOut1.flush() 的行为?
  • @Prateek :我认为在每次写入会话后清除 OutputStream 是一个好习惯。

标签: java sockets


【解决方案1】:

如果您的设备在每条消息上都发送 ACK 并且服务器能够接收到它,那么您可以按照以下方式继续使用您的服务器端程序。
编辑
我已经根据需求分析更新了代码。如果实施后发现任何差异,请告诉我。

Thread.sleep(1000) 不是上述情况的可靠解决方案,因为 我们不知道设备可能需要多长时间才能执行上一个 服务器发送的命令。

    public void run() 
    {

        int i = -1;
        ArrayList<String> list = new ArrayList<String>();
        while ((nextChar=readIn1.read()) != -1) 
        {
            boolean isCompleteMessage = readMessage(nextChar);
            if (isCompleteMessage)
            {
                String[] splitResult = completeMessage .split(",");    
                String header=splitResult[0].trim().substring(0,4);
                if((header.equals("$ACK"))
                {
                    String id = null;
                    if (i != -1)
                    {
                        id = list.get(i);
                        id = id.substring(0,id.indexOf("^"));
                    }
                    //update the message sent from the server as already acknowledge using id extracted above.
                    if ( i == 0)
                    {
                        list.remove(i);
                        if (list.size() == 0)
                        {
                            i = -1;
                        }
                        else
                        {
                            commandText = list.get(i);
                            writeOut1.write(commandText.substring((commandText.indexOf("^")) + 1));
                            writeOut1.write("\r\n");
                            writeOut1.flush(); 
                        }
                    }
                }     
                else
                {
                    //process here the normal message receive from the devices.
                    if (i == -1)
                    {
                        list = getRecords();
                        if (list.size() > 0)
                        {
                            i = 0;
                            commandText = list.get(i);
                            writeOut1.write(commandText.substring((commandText.indexOf("^")) + 1));
                            writeOut1.write("\r\n");
                            writeOut1.flush(); 
                        }
                    }
                    else 
                    {
                        commandText = list.get(i);
                        writeOut1.write(commandText.substring((commandText.indexOf("^")) + 1));
                        writeOut1.write("\r\n");
                        writeOut1.flush(); 
                    }
                } 
                completeMessage = "";
            }   
        }
   }
   public boolean readMessage(int nextChar)
   {
        completeMessage += (char)nextChar;
        if (((char)nextChar) == '*')
        {
            return true;
        }
        else
        {
            return false;
        }
   }
   //Retreive all commands from database and returns the ArrayList containing those commands.
   public ArrayList<String> getRecords()
   {
       ArrayList<String> list = new ArrayList<String>();
       Statement stat = null;
       ResultSet rsOC1 = null;
       try
       {
            stat = con.createStatement();
            rsOC1 = stat.executeQuery("Query for message retrieval from database");
            while (rsOC1.next())
            {
                String sElement = rs0C1.getString("commandID") + "^" + rs0C1.getString("commandText");
                list.add(sElement);
            }
       }
       catch (Exception ex){}
       finally
       {
           if (rs0C1 != null)
           {
               try
               {
                    rs0C1.close();   
               } catch () {}
           }
           if (stat != null)
           {
               try
               {
                    stat.close();   
               } catch () {}
           }
           return list;
       }
   }

【讨论】:

  • @new14:我认为你应该等到服务器收到ACK,然后将下一个命令发送给客户端。
  • @VishalK 我们这里有一个问题,因为在最顶部我们已经有一行 while ((nextChar=readIn1.read()) != -1) 从客户端读取数据。那么,这对您提出的建议有何影响?我们不能阻止 readline,因为它可能需要一些时间来处理和发送 ACK?
  • @VishalK 为什么?除非连接断开,否则 TCP 将传送数据。为什么服务器要在继续之前等待确认?这如何解决任何问题?没有答案。
  • @EJP:正如 Esmond Pitt 在 Fundamental Networking 中所说:为了在一次接收大量数据的应用程序中获得最大性能(例如,发送大量数据的应用程序的另一端),接收方的接收缓冲区需要在上述约束范围内尽可能大,因为 TCP 根据接收方可用的缓冲区空间来限制发送方——发送方可能不会发送数据,除非它知道接收方有空间。如果接收应用程序从缓冲区读取数据的速度很慢,它的接收缓冲区大小需要更大,以免拖延发送方。
  • @EJP:由于我们不能增加接收方的接收缓冲区大小,因为它是一个设备并且它的代码不可用所以我们有两个选择 1. 增加发送方缓冲区大小 2. 发送方只有在接收方处理完数据后(即从客户端收到 Ack 后)才将数据发送给接收方。我没有考虑第一个选项,因为我们仍然不确定设备处理每个命令需要多长时间,因此发送方和接收方缓冲区可能都已满,而客户端(设备)仍在处理上一个命令。所以我认为第二个选项是最合适的。
猜你喜欢
  • 1970-01-01
  • 2015-06-21
  • 2016-08-31
  • 2021-07-29
  • 2019-03-15
  • 1970-01-01
  • 2011-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多