我的网络协议的设计是否正确?

时间:2015-02-19 13:03:37

标签: java sockets tcp

我的网络应用程序出现超时问题。

使用Java我设计了一个以这种方式工作的客户端 - 服务器prrotocol:

  1. 客户端使用套接字tcp连接并连接到服务器

  2. 服务器accept()连接并阻止没有等待请​​求的读取

  3. 客户端请求发送字符串的一些信息或文件"我需要文件X"并阻止直到服务器回答(在发送请求后我刷新我的soketOutputStream

  4. 服务器将信息或文件发送到客户端(此处服务器将文件长度发送给客户端,以便它可以正常读取)

  5. 服务器再次阻止,直到另一个请求到达或客户端完成连接。

  6. 我正在使用服务器接受后获得的相同的conenction套接字,我正在使用flush来结束对话。 我能相信flush会让TCP发送所有数据吗?我也尝试过TCP NO DELAY标志,但它只会让时间更糟......那太奇怪......

    服务器处理文件请求:

        InputStream fin = new FileInputStream(myFile);
        Packet r = new Packet("STREAMREQREPLY", (int)myFile.length(), fin);
        HashMap<String, String> nh = new HashMap<String, String>();
        nh.put("FILE", a);
        r.setHeaders(nh);
        NetworkHandler.sendPacket(r, clientSocket.getOutputStream());
        fin.close();
    

    NetworkHandler发送数据包:

    public static void sendPacket(Packet p, OutputStream os) throws Exception
        {
            synchronized(os)
            {
                String header = "<";
                if(p.getHeaders() != null && !p.getHeaders().isEmpty())
                {
                    Iterator<Entry<String, String>> it = p.getHeaders().entrySet().iterator();
                    while(it.hasNext())
                    {
                        Entry<String, String> e = it.next();
                        if(e.getKey() != null)
                        {
                            if(e.getKey().contains(":") || e.getKey().contains("<") || e.getKey().contains(">"))
                                throw new IllegalArgumentException("Parametros no header não devem conter '<' nem '>' nem ':'");
                        }
                        if(e.getValue() != null)
                        {
                            if(e.getValue().contains(":") || e.getValue().contains("<") || e.getValue().contains(">"))
                                throw new IllegalArgumentException("Parametros no header não devem conter '<' nem '>' nem ':'");
                        }
                        header += e.getKey()+":"+e.getValue()+":";
                    }
                    header = header.substring(0, header.length()-1)+">";
                }
                else
                    header += ">";
    
    
                String cp = "TYPE: "+p.getType()+",DATASIZE: "+p.getDataSize()+header;
    
                os.write(cp.getBytes("ISO-8859-1"));
    
                if(p.getDataSize() > 0)
                {
                    if(p.getInputStream() == null)
                        throw new IllegalArgumentException("No input Stream");
                    IOUtil.copyInputToOutput(p.getInputStream(), os, p.getDataSize());
                }
                os.flush();
            }
        }
    

    IOUtil:

    public static void copyInputToOutput(InputStream in, OutputStream out, int size) throws Exception
        {
            byte[] buf = new byte[8192];
            int total = 0;
            int read = 0;
            while(total < size)
            {
                if(size-total >= buf.length)
                    read = in.read(buf, 0, buf.length);
                else
                    read = in.read(buf, 0, size-total);
                out.write(buf, 0, read);
                total += read;
            }
        }
    

    客户端只使用此方法读取数据包:

    public static Packet readPacket(InputStream is) throws Exception
        {
            synchronized(is)
            {
                ByteArrayOutputStream ba = new ByteArrayOutputStream(1024);
    
                int ch;
    
                //Le o tipo do pacote
                while((ch = is.read()) != 44)
                {
                    if(ch == -1)
                        throw new IOException("Conecção finalizada");
                    ba.write(ch);
                }
                String type = ba.toString("ISO-8859-1");
                if(!type.startsWith("TYPE: "))
                    throw new IllegalArgumentException("Erro ao ler tipo, esperado 'TYPE: ' lido: '"+type+"'");
    
                Packet p = new Packet(type.replace("TYPE: ", ""));
    
                //Le o tamanho dos dados
                ba.reset();
                while((ch = is.read()) != 60)
                {
                    if(ch == -1)
                        throw new IOException("Conecção finalizada");
                    ba.write(ch);
                }
                String dataSize = ba.toString("ISO-8859-1");
                if(!dataSize.startsWith("DATASIZE: "))
                    throw new IllegalArgumentException("Erro ao ler tipo, esperado 'DATASIZE: ' lido: '"+dataSize+"'");
                p.setDataSize( Integer.parseInt(dataSize.replace("DATASIZE: ", "")) );
    
                //Tenta ver se existe algum parametro no header
                ba.reset();
                int hRead = 0;
                while((ch = is.read()) != 62)
                {
                    if(ch == -1)
                        throw new IOException("Conecção finalizada");
                    hRead++;
                    ba.write(ch);
                }
                if(hRead > 2)
                {
                    HashMap<String, String> map = new HashMap<String, String>();
                    String header = ba.toString("ISO-8859-1").replace("<", "").replace(">", "");
                    String[] he = header.split(":");
                    if(he.length%2 != 0)
                        throw new IllegalArgumentException("Header inválido: "+header);
                    for (int i = 0; i < he.length; i=i+2) 
                    {
                        map.put(he[i], he[i+1]);
                    }
                    p.setHeaders(map);
                }
                //Seta os dados no InputStream
                p.setInputStream(is);
                return p;
            }
        }
    

    这一个

    public ByteArrayInputStream getAudioStream(String host, int port, String client, String filial, String code, 
                String style, String audio) throws Exception
        {
            Socket s = connect(host, port);
            HashMap<String, String> map = new HashMap<String, String>();
            //some data in the map
            Packet p = new Packet("STREAMREQ");
            p.setHeaders(map);
            NetworkHandler.sendPacket(p, s.getOutputStream());
    
            Packet r = NetworkHandler.readPacket(s.getInputStream());
            if(r.getType().equals("ERROR"))
                throw new RuntimeException("Erro: "+r.getHeaders().get("ERROR"));
            ByteArrayInputStream bi = IOUtil.toByteArrayInputStream(r.getInputStream(), r.getDataSize());
            return bi;
        }
    

    IOUtil

    public static ByteArrayInputStream toByteArrayInputStream(InputStream is, int size) throws Exception
        {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            copyInputToOutput(is, bout, size);
            return new ByteArrayInputStream(bout.toByteArray());
        }
    

    修改 手动调试我意识到发生错误时服务器没有退出while循环

    public static void copyInputToOutput(InputStream in, OutputStream out, int size) throws Exception
        {
            byte[] buf = new byte[8192];
            int total = 0;
            int read = 0;
            while(total < size)
            {
                if(size-total >= buf.length)
                    read = in.read(buf, 0, buf.length);
                else
                    read = in.read(buf, 0, size-total);
                out.write(buf, 0, read);
                total += read;
                System.out.println("TOTAL: "+total);
                System.out.println("SIZE: "+size);
            }
            System.out.println("FINAL COPY INPUT TO OUTPUT: "+total);
        }
    

    它永远不会打印FINAL COPY ...当错误发生时,客户端会超时并断开连接并且服务器会损坏管道。 这可能意味着超时很短(15秒),我认为它不是或方法实现错误

0 个答案:

没有答案