2014-05-11 4 views
0
package com.common.net; 

import java.io.EOFException; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.StreamCorruptedException; 
import java.net.Socket; 
import java.net.SocketException; 
import java.util.HashMap; 
import java.util.Random; 

public abstract class PacketCommunicator implements Runnable { 

    private Object lastCommandSent; 
    private Object lastCommandReceived; 
    private Object lastPacketReceived; 
    private Object lastPacketSent; 

    protected ObjectInputStream in; 
    protected ObjectOutputStream out; 
    protected Socket socket; 
    private boolean connected; 
    protected boolean encryptionEnabled = false; 
    protected String key = "default"; 

    public HashMap<String, Object> data; 

    protected int sentPackets = 0; 
    protected int receivedPackets = 0; 

    public String getIP() { 
     return socket.getInetAddress().toString(); 
    } 

    public abstract void disconnect(); 

    public abstract void broadcast(String cmd, String data); 

    public abstract void broadcast(Object packet); 

    /** 
    * This is used for the LPacket system which is not recommended for 
    * sensitive data since LPacket's can be decompiled and the functions for 
    * both server and client are visible. 
    * 
    * @param packet 
    */ 
    public abstract void packetReceived(Object packet); 

    /** 
    * This is good for sensitive data 
    * 
    * @param packetID 
    *   ID of packet 
    * @param cmd 
    *   Labeling command 
    * @param data 
    */ 
    public abstract void packetReceived(String cmd, String data); 

    public void toggleEncryption() { 
     encryptionEnabled = !encryptionEnabled; 
    } 

    public boolean isConnected() { 
     return connected; 
    } 

    public void flush() { 
     try { 
      out.flush(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Sends the LPacket to this client 
    * 
    * @param packet 
    */ 
    public void sendPacket(Object packet) { 
     try { 
      sentPackets++; 
      out.flush(); 
      out.writeObject(packet); 
      this.lastPacketSent = packet; 
      out.flush(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void sendPacket(String cmd, String data) { 
     try { 

      sentPackets++; 

      String s = cmd + ":" + sentPackets + "::" + data; 
      out.flush(); 
      if (encryptionEnabled) { 
       out.writeObject(encrypt(key, s)); 
      } else { 
       out.writeObject(s); 
      } 
      out.flush(); 
      lastCommandSent = s; 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    // Constructor class for game client 
    public PacketCommunicator(String server, int port) throws IOException { 
     this(new Socket(server, port), false); 
    } 

    /** 
    * 
    * @param socket 
    * @param onServer 
    *   The Packet Communicator on the server MUST create the input 
    *   stream first This constructor is used for the server 
    */ 
    public PacketCommunicator(Socket socket, boolean onServer) { 
     this.socket = socket; 
     data = new HashMap<String, Object>(); 

     try { 

      if (onServer) { 
       in = new ObjectInputStream(socket.getInputStream()); 
       out = new ObjectOutputStream(socket.getOutputStream()); 
      } else { 
       out = new ObjectOutputStream(socket.getOutputStream()); 
       in = new ObjectInputStream(socket.getInputStream()); 
      } 

      connected = true; 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     Thread t = new Thread(this); 
     t.start(); 

    } 

    /* 
    * @param Manually closes the connection 
    */ 
    public void closeConnection() { 
     connected = false; 
     disconnect(); 
     try { 
      out.flush(); 
      out.close(); 
      in.close(); 
      socket.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void run() { 
     while (this.isConnected()) { 
      try { 

       Object packet = in.readObject(); <---Line 174 
       receivedPackets++; 
       if (packet instanceof String) { 
        this.lastCommandReceived = packet; 
        String packetString = packet.toString(); 
        if (encryptionEnabled) { 
         packetString = decrypt(key, packetString); 
        } 

        String cmd = packetString.substring(0, packetString.indexOf(":")); 

        int packetID = Integer.parseInt(packetString.substring(packetString.indexOf(":") + 1, 
          packetString.indexOf("::"))); 

        String data = packetString.substring(packetString.indexOf("::") + 2); 

        // FServer.log(packetString); 
        if (packetID == receivedPackets) { 

        } else { 
        } 

        packetReceived(cmd, data); 
       } else { 
        this.lastPacketReceived = packet; 
        this.packetReceived(packet); 
       } 
      } catch (StreamCorruptedException e) { 
       connected = false; 
       e.printStackTrace(); 
      } catch (EOFException e) { 
       // This usually happens when someone manually disconnects, 
       // really not too big of an issue 
       connected = false; 
      } catch (ClassNotFoundException e) { 
       e.printStackTrace(); 
      } catch (SocketException e) { 
       // Closed client 
       connected = false; 
      } catch (IOException e) { 
       connected = false; 
       e.printStackTrace(); 
      } 
     } 
     System.out.println("Last packet sent: " + lastPacketSent); 
     System.out.println("Last packet received: " + lastPacketReceived); 

     System.out.println("Last command sent: " + lastCommandSent); 
     System.out.println("Last command received: " + lastCommandReceived); 
     disconnect(); 
    } 

    public static String encrypt(String key, String text) { 
     long finalKey = 0; 
     for (int i = 0; i < key.length(); i++) { 
      long tempKey = key.charAt(i); 
      tempKey *= 128; 
      finalKey += tempKey; 
     } 
     Random generator = new Random(finalKey); 
     String returnString = ""; 
     for (int i = 0; i < text.length(); i++) { 
      if (text.charAt(i) == ' ') { 
       returnString += text.charAt(i); 
      } else { 
       int temp = text.charAt(i); 
       temp += generator.nextInt(95); 
       if (temp > 126) { 
        temp -= 95; 
       } 
       returnString += (char) temp; 
      } 
     } 
     return returnString; 
    } 

    public static String decrypt(String key, String text) { 
     long finalKey = 0; 
     for (int i = 0; i < key.length(); i++) { 
      long tempKey = key.charAt(i); 
      tempKey *= 128; 
      finalKey += tempKey; 
     } 
     Random generator = new Random(finalKey); 
     String returnString = ""; 
     for (int i = 0; i < text.length(); i++) { 
      if (text.charAt(i) == ' ') { 
       returnString += text.charAt(i); 
      } else { 
       int temp = text.charAt(i); 
       temp -= generator.nextInt(95); 
       if (temp < 36) { 
        temp += 95; 
       } 
       if (temp > 126) { 
        temp -= 95; 
       } 
       returnString += (char) temp; 
      } 
     } 
     return returnString; 
    } 

} 


java.io.StreamCorruptedException: invalid type code: 00 
    at java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(Unknown Source) 
    at java.io.ObjectInputStream$BlockDataInputStream.refill(Unknown Source) 
    at java.io.ObjectInputStream$BlockDataInputStream.read(Unknown Source) 
    at java.io.DataInputStream.readInt(Unknown Source) 
    at java.io.ObjectInputStream$BlockDataInputStream.readInt(Unknown Source) 
    at java.io.ObjectInputStream.readInt(Unknown Source) 
    at java.util.ArrayList.readObject(Unknown Source) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at java.io.ObjectStreamClass.invokeReadObject(Unknown Source) 
    at java.io.ObjectInputStream.readSerialData(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source) 
    at java.io.ObjectInputStream.readSerialData(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.readObject(Unknown Source) 
    at com.common.net.PacketCommunicator.run(PacketCommunicator.java:174) 
    at java.lang.Thread.run(Unknown Source) 

기본적으로, 때때로. 그리고 때로는 (시간의 25 %)이 오류가 나타나기 만한다는 것을 의미합니다.스트림 손상된 예외 잘못된 코드 : 00

public void teleportToMap(String mapName, int tileX, int tileY) { 
    player.map = mapName; 
    currentMap = Server.mapHandler.getMap(mapName); 

    MapPacket mp = new MapPacket(currentMap, tileX, tileY); 
    sendPacket(mp); 

} 

을 그리고 지금 여기 MapPacket의 조각이다 : 나는 서버에서이를 보내려고 할 때 이 발생합니다. MapPacket은 기본적으로 objectinputstream으로부터받은 경우 PacketToClient에서 단지 applyToClient를 호출하는 PacketToClient를 확장합니다.

package com.common.packet.packets.client; 

import com.badlogic.gdx.Gdx; 
import com.client.Forest; 
import com.client.net.ServerConnection; 
import com.client.scenes.GameScene; 
import com.common.map.Map; 
import com.common.movable.Movable; 
import com.common.packet.PacketToClient; 

import java.util.ArrayList; 

public class MapPacket extends PacketToClient { 

    private static final long serialVersionUID = 1L; 

    String mapName; 
    ArrayList<Movable> ground; 

    int tileX, tileY; 

    public MapPacket(Map map, int tileX, int tileY) { 
     this.mapName = map.name; 
     this.ground = map.getGround(); 
     this.tileX = tileX; 
     this.tileY = tileY; 
    } 

    @Override 
    public void applyPacketToClient(ServerConnection server) { 
     Gdx.app.postRunnable(new Runnable() { 
      public void run() { 
       GameScene.currentMap = null; 
       GameScene.mapRenderer.setCurrentMap(null); 
       Map map = ServerConnection.loadMapFromServer(mapName); 
       map.setGround(ground); 
       GameScene.mapRenderer.setCurrentMap(map); 
       GameScene.currentMap = map; 
       Forest.player.setTilePosition(tileX, tileY); 
      } 
     }); 
    } 

} 

나는 이것에 대해 많은 연구를했지만, 계속 감기에 걸렸다. 또한 때로는 스트림 활성 예외가 발생합니다.

답변

1

두 개 이상의 스레드에서 동시에 스트림에 쓰거나 스트림에서 읽는 중입니다. 이것이 '스트림 활성'에 대한 유일한 설명이며, 다른 문제도 잘 설명 할 수 있습니다.

NB 다른 순서로 스트림을 만드는 일은 필요하지 않습니다. 항상 ObjectOutputStream를 먼저 작성하십시오. Runnable의 run() 메소드에서 스트림을 작성해야한다. Runnable의 위치는 사용자가 아닌 Runnable이다. I/O는 해당 스레드에서만 수행되어야한다.

+0

아. 괜찮아. 그것은 당신의 아이디어가 StreamCorruptedException을 제거한 것처럼 보입니다. (또는 그렇게 보일 수도 있습니다. 가끔씩 만 발생하기 때문에 이걸로 말하기가 어렵습니다.) 패킷을 보낼 때 어떨까요? 나도 항상 스레드에서 그렇게해야합니까? – Buzzyboy

+0

이론적으로 패킷을 보내는 PacketCommunicator에 다른 스레드를 만들 수 있습니다. sendPacket가 호출되면 Packet을 버퍼 배열에 추가합니다. 전송할 항목이 없을 때까지 루프를 반복하고 더 추가 될 때까지 기다립니다. 이게 합리적일까요? – Buzzyboy

+0

아. 나는 지금 본다. writeObject 전에 현재 스레드의 이름을 인쇄하기로 결정했다. 그것에 쓰는 3 개의 쓰레드가있다. 정말 고맙습니다! – Buzzyboy

관련 문제