2012-12-21 9 views
6

Chcę wysłać więcej niż jedną losową wartość przez Socket. Myślę, że tablica jest najlepszym sposobem, aby je wysłać .. Ale nie wiem jak napisać tablicę do Socket outputStream?jak napisać tablicę do outputStream w Javie

Moja Java Class

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.Socket; 
import java.io.*; 
import java.util.Random; 

class NodeCommunicator { 

public static void main(String[] args) { 
try { 
    Socket nodejs = new Socket("localhost", 8181); 

     Random randomGenerator = new Random(); 
     for (int idx = 1; idx <= 1000; ++idx){ 
      Thread.sleep(500); 
      int randomInt = randomGenerator.nextInt(35); 
      sendMessage(nodejs, randomInt + " "); 
      System.out.println(randomInt); 
     } 

     while(true){ 
      Thread.sleep(1000); 
     } 

} catch (Exception e) { 
    System.out.println("Connection terminated..Closing Java Client"); 
    System.out.println("Error :- "+e); 
    } 

} 
     public static void sendMessage(Socket s, String message) throws IOException { 
      s.getOutputStream().write(message.getBytes("UTF-8")); 
      s.getOutputStream().flush(); 
     } 




} 
+3

co jest nie tak z tym kodem? co i jak nie działa? –

+0

jaki jest błąd, który otrzymujesz – Shurmajee

+0

Z jego wyjaśnienia wygląda na to, że chce wysłać tablicę wiadomości w jednym wywołaniu, aby napisać(), zamiast iterować po tablicy i wysyłać każdy ciąg za pomocą ciągu znaków –

Odpowiedz

7

Użyj pary java.io.DataOutputStream/DataInputStream, wiedzą, jak czytać ints. Wyślij informacje jako pakiet o długości + liczby losowe.

nadawca

Socket sock = new Socket("localhost", 8181); 
DataOutputStream out = new DataOutputStream(sock.getOutputStream()); 
out.writeInt(len); 
for(int i = 0; i < len; i++) { 
     out.writeInt(randomGenerator.nextInt(35)) 
... 

odbiornik

DataInputStream in = new DataInputStream(sock.getInputStream()); 
int len = in.readInt(); 
for(int i = 0; i < len; i++) { 
     int next = in.readInt(); 
... 
+0

+1 za wpisanie logiki dla nadawcy i odbiorcy –

2

radziłbym po prostu złączyć wartości int w ciąg przy użyciu jakiegoś separatora np @@, a następnie przesyła ostateczny łączony ciąg na raz. Po stronie odbiorczej, po prostu podzielić ciąg przy użyciu samego ogranicznika, aby uzyskać int[] tylną np

Random randomGenerator = new Random(); 
    StringBuilder numToSend = new StringBuilder(""); 
    numToSend.append(randomGenerator.nextInt(35)); 

    for (int idx = 2; idx <= 1000; ++idx){ 
     Thread.sleep(500); 
     numToSend.append("@@").append(randomGenerator.nextInt(35)); 
    } 
    String numsString = numToSend.toString(); 
    System.out.println(numsString); 
    sendMessage(nodejs, numsString); 

po stronie odbiorczej, uzyskać ciąg i podzielić jako:

Socket remotejs = new Socket("remotehost", 8181); 
    BufferedReader in = new BufferedReader(
           new InputStreamReader(remotejs.getInputStream())); 
    String receivedNumString = in.readLine(); 
    String[] numstrings = receivedNumString.split("@@"); 
    int[] nums = new int[numstrings.length]; 
    int indx = 0; 
    for(String numStr: numstrings){ 
    nums[indx++] = Integer.parseInt(numStr); 
    } 
+0

+1 Używanie @@ jest być może przesadą dla liczb. Zrobiłaby to zwykła przestrzeń. –

+0

@PeterLawrey Zgadzam się. Wspomniałem już o użyciu jakiegokolwiek ogranicznika. –

0

jeśli chcesz wysłać więcej niż jedną losową wartość do gniazda, wybierz prosty format i obie strony zgadzają się na to (nadawca i odbiornik), na przykład możesz po prostu wybrać separator taki jak ; i utworzyć ciąg z wszystkimi wartościami z tym separatorem, a następnie wysłać

1

Cóż, strumień jest strumieniem bajtów, więc musisz zakodować dane w sekwencji bajtów i dekodować je po stronie odbiorczej. Sposób zapisywania danych zależy od sposobu kodowania.

jak cyfry od 0 do 34 mieści się w jednym bajcie, może być tak proste, jak:

outputStream.write(randomNumber); 

, a z drugiej strony:

int randomNumber = inputStream.read(); 

Oczywiście spłukiwania strumień po każdy bajt nie jest zbyt wydajny (ponieważ generuje pakiet sieciowy dla każdego bajtu, a każdy pakiet sieciowy zawiera dziesiątki bajtów informacji nagłówka i routingu ...). Jeśli wydajność ma znaczenie, prawdopodobnie będziesz chciał użyć również BufferedOutputStream.

3

tablice Java są rzeczywiście Object s, a ponadto ich implementować interfejs Serializable. Więc możesz serializować tablicę, pobrać bajty i wysłać je przez gniazdo. Należy to zrobić:

public static void sendMessage(Socket s, int[] myMessageArray) 
    throws IOException { 
    ByteArrayOutputStream bs = new ByteArrayOutputStream(); 
    ObjectOutputStream os = new ObjectOutputStream(bs); 
    os.writeObject(myMessageArray); 
    byte[] messageArrayBytes = bs.toByteArray(); 
    s.getOutputStream().write(messageArrayBytes); 
    s.getOutputStream().flush(); 
} 

Co naprawdę miłe jest to, że działa nie tylko dla int[] ale za każdym Serializable obiektu.

Edit: Myśląc o niej znowu, jest to jeszcze prostsze:

nadawca:

public static void sendMessage(Socket s, int[] myMessageArray) 
    throws IOException { 
    OutputStream os = s.getOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(os); 
    oos.writeObject(myMessageArray); 
} 

odbiornik:

public static int[] getMessage(Socket s) 
    throws IOException { 
    InputStream is = s.getInputStream(); 
    ObjectInputStream ois = new ObjectInputStream(is); 
    int[] myMessageArray = (int[])ois.readObject(); 
    return myMessageArray; 
} 

Wyjeżdżam mój pierwsza odpowiedź również jako (to als o działa i) jest przydatne do pisania obiektów do UDP DatagramSockets i DatagramPackets gdzie nie ma strumienia.

+0

należy wysłać długość, w przeciwnym razie po tym nie będzie można nic czytać. –

+0

@PeterLawrey wyjaśnić? 'write (byte [] b)' zapisuje 'b.length' bajtów do strumienia. – AFS

+0

Powiedzmy, że dzwonisz do tego dwa razy, skąd wiesz, kiedy skończy się pierwsza tablica i rozpocznie się następna tablica? tj. spróbuj odczytać ten format, a napotkasz to bardzo trudno. btw +1 –

1

Można więc porównać alternatywne formaty, które napisałem, szablon, który pozwala na użycie dowolnego formatu, według własnego życzenia, lub porównać alternatywy.

abstract class DataSocket implements Closeable { 
    private final Socket socket; 
    protected final DataOutputStream out; 
    protected final DataInputStream in; 

    DataSocket(Socket socket) throws IOException { 
     this.socket = socket; 
     out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); 
     in = new DataInputStream(new BufferedInputStream(socket.getInputStream())); 
    } 

    public void writeInts(int[] ints) throws IOException { 
     writeInt(ints.length); 
     for (int i : ints) 
      writeInt(i); 
     endOfBlock(); 
    } 

    protected abstract void writeInt(int i) throws IOException; 

    protected abstract void endOfBlock() throws IOException; 

    public int[] readInts() throws IOException { 
     nextBlock(); 
     int len = readInt(); 
     int[] ret = new int[len]; 
     for (int i = 0; i < len; i++) 
      ret[i] = readInt(); 
     return ret; 
    } 

    protected abstract void nextBlock() throws IOException; 

    protected abstract int readInt() throws IOException; 

    public void close() throws IOException { 
     out.close(); 
     in.close(); 
     socket.close(); 
    } 
} 

binarny format typu int 4-bajtowe

class BinaryDataSocket extends DataSocket { 
    BinaryDataSocket(Socket socket) throws IOException { 
     super(socket); 
    } 

    @Override 
    protected void writeInt(int i) throws IOException { 
     out.writeInt(i); 
    } 

    @Override 
    protected void endOfBlock() throws IOException { 
     out.flush(); 
    } 

    @Override 
    protected void nextBlock() { 
     // nothing 
    } 

    @Override 
    protected int readInt() throws IOException { 
     return in.readInt(); 
    } 
} 

bit stopu kodowany binarnie z jednego bajtu 7 bitów.

class CompactBinaryDataSocket extends DataSocket { 
    CompactBinaryDataSocket(Socket socket) throws IOException { 
     super(socket); 
    } 

    @Override 
    protected void writeInt(int i) throws IOException { 
     // uses one byte per 7 bit set. 
     long l = i & 0xFFFFFFFFL; 
     while (l >= 0x80) { 
      out.write((int) (l | 0x80)); 
      l >>>= 7; 
     } 
     out.write((int) l); 
    } 

    @Override 
    protected void endOfBlock() throws IOException { 
     out.flush(); 
    } 

    @Override 
    protected void nextBlock() { 
     // nothing 
    } 

    @Override 
    protected int readInt() throws IOException { 
     long l = 0; 
     int b, count = 0; 
     while ((b = in.read()) >= 0x80) { 
      l |= (b & 0x7f) << 7 * count++; 
     } 
     if (b < 0) throw new EOFException(); 
     l |= b << 7 * count; 
     return (int) l; 
    } 
} 

tekst zakodowany za pomocą nowej linii na końcu.

class TextDataSocket extends DataSocket { 
    TextDataSocket(Socket socket) throws IOException { 
     super(socket); 
    } 

    private boolean outBlock = false; 

    @Override 
    protected void writeInt(int i) throws IOException { 
     if (outBlock) out.write(' '); 
     out.write(Integer.toString(i).getBytes()); 
     outBlock = true; 
    } 

    @Override 
    protected void endOfBlock() throws IOException { 
     out.write('\n'); 
     out.flush(); 
     outBlock = false; 
    } 

    private Scanner inLine = null; 

    @Override 
    protected void nextBlock() throws IOException { 
     inLine = new Scanner(in.readLine()); 
    } 

    @Override 
    protected int readInt() throws IOException { 
     return inLine.nextInt(); 
    } 
} 
0

Android Socket SERVER Example zmodyfikowane, aby otrzymać tablice liczb całkowitych zamiast strun:

... 
class CommunicationThread implements Runnable { 

    private ObjectInputStream input; 

    public CommunicationThread(Socket clientSocket) { 

     try { 

      this.input = new ObjectInputStream(clientSocket.getInputStream()); 

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

    public void run() { 

     while (!Thread.currentThread().isInterrupted()) { 

      try { 

       int[] myMessageArray = (int[]) input.readObject(); 

       String read = null; 
       read = String.format("%05X", myMessageArray[0] & 0x0FFFFF); 
       int i = 1; 
       do { 
        read = read + ", " + String.format("%05X", myMessageArray[i] & 0x0FFFFF); 
        i++; 
       } while (i < myMessageArray.length); 
       read = read + " (" + myMessageArray.length + " bytes)"; 

       updateConversationHandler.post(new updateUIThread(read)); 

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