6

私は DatagramPacket を送信しようとしていますが、同じパケットを再送信する必要があるか、次のパケットを送信する必要があるかを知るために、サーバーからの確認応答を待つ必要があります..

クライアントで同じソケットを使用して、データパケットを送信し、確認応答 (ack) を受信し、サーバー側でも同じように、データパケットを受信して​​確認応答を送信するために使用される別のソケットを使用しています。クライアント..

1 つ目の問題は、クライアントがデータパケットを送信し、サーバーがそれを受信して​​から、確認応答をクライアントに送信するが、クライアントが確認応答パケットの受信をブロックすることです。

どこに問題があるかを特定するために System.out.println をいくつか作成していますが、この問題の解決策が見つかりませんでした。

2番目の問題は、サーバーがまだ常にデータを受信して​​おり、クライアントが何かを送信するのを待たないことです。受信されない確認応答を待っているため、クライアントは最初のパケットを送信した後にブロックされますが、常にサーバー側に出力されます!

クライアントのコードは次のとおりです。

package blatt7;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.zip.CRC32;




public class FileSender { 


String zielRechner;
String filePath;
InetAddress host;
File file;
FileInputStream fis;
int readLength;
int sequenceNr = 0;
int receivedSeqNr = 1;
static int port = 7777;
int packetNr = 0;
byte[] packet = new byte[1216];
byte[] data = new byte[1200];
byte[] header = new byte[16];
byte[] readLengthByte = new byte[4];
byte[] sequenceNrByte = new byte[4];
byte[] checksumByte = new byte[8];
byte[] ackBuffer = new byte[4];
CRC32 checksumCalculator = new CRC32();
DatagramPacket dp;
DatagramPacket ackPacket;
DatagramSocket sendSocket = null;
//DatagramSocket ackSocket = null;
static boolean ackReceived = true;

public FileSender(String zielRechner, String filePath) throws UnknownHostException, FileNotFoundException {
    this.zielRechner = zielRechner;
    this.filePath = filePath;
    this.host = InetAddress.getByName(zielRechner);
    this.file = new File(filePath);
    fis = new FileInputStream(file);        
}

public void sendFile() throws IOException {

    while((readLength = fis.read(data)) != -1) {
        if (sequenceNr == 1)
            sequenceNr = 0;
        else
            sequenceNr = 1;

        readLengthByte = intToBytes(readLength);
        sequenceNrByte = intToBytes(sequenceNr);

        for(int i=0; i<4; i++) {
            header[8+i] = readLengthByte[i];                
        }

        for(int i=0; i<4; i++) {
            header[12+i] =sequenceNrByte[i];                
        }

        int j=0; 
        for (int i=0; i<packet.length; i++) {
            if (i < header.length) 
                packet[i] = header[i];
            else { 
                packet[i] = data[j];
                j++;
            }
        }

        checksumCalculator.reset();
        checksumCalculator.update(packet,8,8+readLength);
        checksumByte = longToBytes(checksumCalculator.getValue());

        for(int i=0; i < 8; i++) {
            packet[i] = checksumByte[i];
        }

        dp = new DatagramPacket(packet, packet.length, host, port);

        while(receivedSeqNr == sequenceNr && ackReceived) {
            try {
                ackReceived = false;
                sendSocket = new DatagramSocket();
                sendSocket.send(dp);
                sendSocket.setSoTimeout(10000);
                packetNr++;
                System.out.println("Packet sent with seqNr: " + sequenceNr + " and length: " + bytesToInt(readLengthByte, 0) + " - PACKET NR: " + packetNr);
                ackPacket = new DatagramPacket(ackBuffer, ackBuffer.length);
                System.out.println("TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                sendSocket.receive(ackPacket);
                System.out.println("Receiving ACK!!");
                ackReceived = true;
                ackBuffer = ackPacket.getData();
                receivedSeqNr = bytesToInt(ackBuffer,0);
                System.out.println("got SequenceNr with receivedSeq-Nr: " + receivedSeqNr);
            } catch (SocketTimeoutException e) {
                    e.printStackTrace();
                    break;
            }
        }   
    }

    fis.close();
    System.out.println("Transfer Completed Successfully!");
    sendSocket.close();
}

public static byte[] longToBytes(long value) {
    ByteBuffer buffer = ByteBuffer.allocate(8);
    buffer.putLong(value);
    return buffer.array();
}

public static long bytesToLong(byte[] bytes, int index) {
    ByteBuffer buffer = ByteBuffer.allocate(8);
    buffer.put(bytes);
    buffer.flip();//need flip 
    return buffer.getLong(index);
}

public static byte[] intToBytes(int value) {
    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.putInt(value);
    return buffer.array();
}

public static int bytesToInt(byte[] bytes, int index) {
    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.put(bytes);
    buffer.flip();//need flip 
    return buffer.getInt(index);
}

public static void main(String[] args) throws IOException,ClassNotFoundException {

    FileSender sender = new FileSender("localhost", "C:/Users/Kb/Desktop/Deepophile - Psychedelic Sessions.wav");
    sender.sendFile();

}

}

サーバーのコードは次のとおりです。

package blatt7;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.zip.CRC32;

public class FileReceiver {

byte[] incomingBuffer;
DatagramPacket incomingPacket;
DatagramSocket receiveSocket;
DatagramPacket ackPacket;
int packetCounter = 0;
int dataLength;
int receivedSeqNr;
long calculatedChecksum;
long receivedChecksum;
CRC32 checksumCalculator = new CRC32();
byte[] dataLengthByte = new byte[4];
byte[] receivedSeqNrByte = new byte[4];
byte[] receivedChecksumByte = new byte[8];
byte[] ackArray;


public FileReceiver() throws SocketException {
    incomingBuffer = new byte[1500];
    incomingPacket = new DatagramPacket(incomingBuffer, incomingBuffer.length);
}

public void receive() throws IOException {

    receiveSocket = new DatagramSocket(FileSender.port);
    receiveSocket.setSoTimeout(10000);
    System.out.println("Server socket created. Waiting for incoming data...");

    while(true && FileSender.ackReceived)
    {   
        receiveSocket.receive(incomingPacket);
        packetCounter++;

        for (int i=0; i <4; i++) {
            dataLengthByte[i] = incomingBuffer[8+i];
        }
        dataLength = FileSender.bytesToInt(dataLengthByte,0);

        checksumCalculator.reset();
        checksumCalculator.update(incomingBuffer, 8, dataLength+8);             
        calculatedChecksum = checksumCalculator.getValue();


        for (int i=0; i <4; i++) {
            receivedSeqNrByte[i] = incomingBuffer[12+i];
        }
        receivedSeqNr = FileSender.bytesToInt(receivedSeqNrByte,0);


        for (int i=0; i <8; i++) {
            receivedChecksumByte[i] = incomingBuffer[i];
        }
        long receivedChecksum = FileSender.bytesToLong(receivedChecksumByte,0);

        System.out.println("Got packet with checksum: " + receivedChecksum);
        System.out.println("Server-calculated checksum: " + calculatedChecksum);
        System.out.println("Got packet with seqNr: " + receivedSeqNr + " and length: " + dataLength);

        if (calculatedChecksum != receivedChecksum)  {
            sendACK(receivedSeqNr);
            System.out.println("Packet have erros(s)! It must be sent another time!");
        }
        else if(calculatedChecksum == receivedChecksum && receivedSeqNr == 1) {
            sendACK(0);
            System.out.println("SeqNr '0' sent");
        }
        else if (calculatedChecksum == receivedChecksum && receivedSeqNr == 0) {
            sendACK(1);
            System.out.println("SeqNr '1' sent");
        }
    }
}

public void sendACK(int seqNum) throws IOException {
    byte[] ackArray = FileSender.intToBytes(seqNum);
    ackPacket = new DatagramPacket(ackArray, ackArray.length, InetAddress.getByName("localhost"), FileSender.port);
    receiveSocket.send(ackPacket);      
}

public static void main(String[] args) throws IOException,ClassNotFoundException {
    FileReceiver receiver = new FileReceiver();
    receiver.receive();     
}

}

問題がどこにあるかを確認するためにそれを実行することができます...この問題を解決する方法があれば教えてください!

どうもありがとうございました!

受信したファイルの場所を誰か教えてもらえますか? または、コードを保存する場所を選択するには、どのようにコードを変更すればよいですか??

4

2 に答える 2

3

はい、可能です。あなたの問題は、ACK データグラムを送信するときにターゲットのアドレス: ポートが間違っていることです。受信した DatagramPacket からターゲットの address:port を取得するか、単純にそのデータグラムを別のデータで ACK データグラムとして再利用する必要があります。

于 2012-12-30T01:18:23.193 に答える
1

サーバーはどのようにして独自のポートを使用してクライアントに送信できますか?サーバーのポートでサーバーからクライアントにACKを送信しています。受信したパケットからクライアントのUDPポートを取得し、そのポートにデータを送信する必要があります。

編集

SendACKメソッドのサーバーを次のように変更します。

ackPacket = new DatagramPacket(ackArray, ackArray.length, InetAddress.getByName("localhost"), incomingPacket.getPort());

そして、実行してコードを分析します。

于 2012-12-29T20:50:34.710 に答える