如何设置java UDP数据报数据包的前2个字节?
我有一个客户端服务器程序试图发送一个jpg文件 我试图向UDP数据包添加一个确认字节和数据的BlockNumber字节。我在这部分代码中遇到了问题(这部分代码只是来自客户端程序的数据块处理代码): 上面的代码不适用于我的服务器,服务器是由老师制作的。我已经检查了服务器代码,看起来很棒 出于某种原因,它挂在应该发送包含整数的确认字节的部分,“3”表示“已确认”。它应该在buff.array()的零位置包含ACK字节。但是服务器说没有收到确认字节 TftpUtil的开头是这样的:如何设置java UDP数据报数据包的前2个字节?,java,udp,datagram,Java,Udp,Datagram,我有一个客户端服务器程序试图发送一个jpg文件 我试图向UDP数据包添加一个确认字节和数据的BlockNumber字节。我在这部分代码中遇到了问题(这部分代码只是来自客户端程序的数据块处理代码): 上面的代码不适用于我的服务器,服务器是由老师制作的。我已经检查了服务器代码,看起来很棒 出于某种原因,它挂在应该发送包含整数的确认字节的部分,“3”表示“已确认”。它应该在buff.array()的零位置包含ACK字节。但是服务器说没有收到确认字节 TftpUtil的开头是这样的: public cl
public class TftpUtil {
//read request packet
public static final byte RRQ = 1;
//data packet
public static final byte DATA = 2;
//ack packet
public static final byte ACK = 3;
//error packet
public static final byte ERROR = 4;
//the maximum number of resent
public static final int MAX_RESEND = 5;
//data buffer size: 512
public static int DATA_BUFFER_SIZE = 512;
//packet buffer size: 2 bytes header + 512 bytes file data;
public static int PACKET_BUFFER_SIZE = DATA_BUFFER_SIZE + 2;
}
服务器所做的是发送一个.jpg文件,数据块为512字节。服务器检测到已建立连接,并尝试发送文件。它发送第一个数据块,这似乎通过了,因为当我检查文件夹时,有一个512字节的asd.jpg文件。但是当客户端返回ACK字节时,服务器会说它不正确并超时
你能看到我粘贴的代码有什么问题吗?或者我应该粘贴更多的代码吗
谢谢
更新完整服务器代码:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class server_v004 {
private InetAddress serverAddress;
private int serverPort;
private DatagramSocket serverSocket;
private static final ExecutorService exec = Executors.newFixedThreadPool(10);
public void startServer()
{
try {
String serverIpAddress = "192.168.1.32";
InetAddress echoServerIP = InetAddress.getByName(serverIpAddress);
serverSocket = new DatagramSocket(serverPort, echoServerIP);
System.out.println("TftpServer on port " + serverSocket.getLocalPort());
while(true) {
byte[] buf = new byte[1472];
DatagramPacket p = new DatagramPacket(buf, 1472);
System.out.println("waiting for connection ....");
serverSocket.receive(p);
server_v004ServerWorker worker = new server_v004ServerWorker(p);
exec.execute(worker);
}
}
catch(Exception e) {
System.err.println("Exception: " + e);
}
serverSocket.close();
return;
}
public static void main(String[] args) {
server_v004 tftpServer = new server_v004();
//tftpServer.checkArgs(args);
try{
tftpServer.parseArgsAndInit(args);
tftpServer.startServer();
}
catch(Exception e){
e.printStackTrace();
}
}
private void checkArgs(String[] args){
if(args.length <0) { //<1 //<2
System.out.println("Usage: TftpServer"); //server_port server_ip
System.exit(0);
}
}
private void parseArgsAndInit(String[] args) throws Exception{
//serverAddress = InetAddress.getByName(args[0]);
serverPort = 12345; //Integer.parseInt(args[1]);
}
}
class server_v004ServerWorker implements Runnable
{
//use to store RRQ request
private DatagramPacket req;
//client address who sent the RRQ request
private SocketAddress clientAddress;
//socket used to send the file data packets to client
private DatagramSocket sendfileSocket;
//byte buffer to store the file data
private byte[] dataBuffer = new byte[TftpUtil.DATA_BUFFER_SIZE];
//the first block sequence
private byte currentBlockSeq = 1;
//use to retrieve the ack packet, only two bytes long
private DatagramPacket ackDP = new DatagramPacket(new byte[2], 2);
private int TIME_OUT = 1000; //1 second
public void run(){
try{
sendfileSocket = new DatagramSocket(69);
System.out.println("TftpServer sending a file on port " + sendfileSocket.getLocalPort());
byte pType = TftpUtil.checkPacketType(req);
clientAddress = req.getSocketAddress();
//checking if the first packet from client is a RRQ packet
if(pType == TftpUtil.RRQ){
String filename = getFileName(req);
System.out.println("Requested file name:" + filename);
//if the file doesn't exist, send ERROR packet and close socket
if(!(new File(filename)).exists()) {
DatagramPacket errorDP = TftpUtil.packErrorPacket(filename);
errorDP.setSocketAddress(clientAddress);
sendfileSocket.send(errorDP);
}
else{
//the file does exist, send file
sendfile(filename);
}
}// end if
}catch(Exception e){
e.printStackTrace();
}
sendfileSocket.close();
return;
}
private void sendfile(String filename) throws Exception{
FileInputStream fileInput = new FileInputStream(filename);
while(true){
int rec = fileInput.read(dataBuffer);
//the file size is a multiple of 512, send empty packet
if(rec == -1){
sendDataPacket(new byte[0],0);
System.out.println("The last packet [0 byte in size]:#"+currentBlockSeq);
break;
}
//send a file data packet
boolean successed = sendDataPacket(dataBuffer,rec);
//tried five times
if (!successed) {
System.out.println("Tried five times, give up");
System.exit(0);
}
// the last packet (the file size if not a multiple of 512)
if (rec < 512 && rec > 0 ) {
System.out.println("The last packet ["+rec+" bytes in size]:#"+currentBlockSeq);
break;
}
currentBlockSeq++;
}//while
fileInput.close();
}
//
private boolean sendDataPacket(byte[] databuffer,int length) throws Exception{
int resendCount = 0;
DatagramPacket dataPacket = packFileDataPacket(databuffer,length);
//try five times
while(resendCount < TftpUtil.MAX_RESEND){
try{
sendfileSocket.send(dataPacket);
sendfileSocket.setSoTimeout(TIME_OUT);
System.out.println("sent data block #"+currentBlockSeq+", waiting for ack #" + currentBlockSeq);
//ack arrives
sendfileSocket.receive(ackDP);
byte ackedBlockseq = TftpUtil.extractACKNumber(ackDP);
System.out.println("received ack #" + ackedBlockseq);
if(ackedBlockseq != currentBlockSeq) {
//the acked block seq is not the seq of block sent
//ignore this ack and resend
resendCount++;
continue;
}
//this data packet has been acked, return
return true;
}//end of try
catch(SocketTimeoutException ste){
resendCount++;
System.out.println("timeout #" + resendCount );
}
}//end of while
return false;
}
private DatagramPacket packFileDataPacket(byte[] dataBuffer, int length){
int packetLength = 2 + length;//type (1) + block seq (1) + data length
ByteBuffer byteBuffer = ByteBuffer.allocate(packetLength);
byteBuffer.put(TftpUtil.DATA);//type
byteBuffer.put(currentBlockSeq);//block seq
byteBuffer.put(dataBuffer,0,length);//data
DatagramPacket dataPacket = new DatagramPacket(byteBuffer.array(), packetLength);
dataPacket.setSocketAddress(clientAddress);
return dataPacket;
}
private String getFileName(DatagramPacket dataDP){
byte[] data = dataDP.getData();
int dataLength = dataDP.getLength();
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength-1);
//remove the packet type (RRQ)
byteBuffer.put(data,1,dataLength-1);
return new String(byteBuffer.array());
}
public server_v004ServerWorker(DatagramPacket req)
{
this.req = req;
}
}
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.net.DatagramPacket;
导入java.net.DatagramSocket;
导入java.net.InetAddress;
导入java.net.SocketAddress;
导入java.net.SocketTimeoutException;
导入java.nio.ByteBuffer;
导入java.util.concurrent.Executors;
导入java.util.concurrent.ExecutorService;
公共类服务器\u v004{
私有地址服务器地址;
专用int服务器端口;
私有DatagramSocket服务器套接字;
private static final ExecutorService exec=Executors.newFixedThreadPool(10);
public void startServer()
{
试一试{
字符串serverIpAddress=“192.168.1.32”;
InetAddress echoServerIP=InetAddress.getByName(服务器IP地址);
serverSocket=新的DatagramSocket(serverPort,echoServerIP);
System.out.println(“端口上的TftpServer”+serverSocket.getLocalPort());
while(true){
字节[]buf=新字节[1472];
DatagramPacket p=新的DatagramPacket(buf,1472);
System.out.println(“等待连接…”);
serverSocket.receive(p);
服务器\u v004ServerWorker=新服务器\u v004ServerWorker(p);
执行(工人);
}
}
捕获(例外e){
System.err.println(“异常:+e”);
}
serverSocket.close();
返回;
}
公共静态void main(字符串[]args){
服务器_v004 tftpServer=新服务器_v004();
//tftpServer.checkArgs(args);
试一试{
tftpServer.parseArgsAndInit(args);
tftpServer.startServer();
}
捕获(例外e){
e、 printStackTrace();
}
}
私有void checkArgs(字符串[]args){
如果(args.length我们可能会使用该服务器代码,只是为了查看实际需要的代码。我们还可以使用生成的错误消息。要调试此代码,请在您自己的计算机上同时设置客户端和服务器,以便您可以查看两端的操作。您需要同时查看这两个代码,或者您只是猜测实际问题是什么。我可以同时看到d一定要在本地运行它。我打算使用wireshark,这有用吗?如果它在本地工作,你应该和你的老师谈谈。问题可能在他或她这方面。你能找到服务器可能会采取的错误路径吗?服务器可能会产生什么错误消息?你在哪里可以找到这些错误?哦,说到本地与远程:这是我的问题s UDP。您确定数据包正在到达服务器吗?如果这些数据包有可能被丢弃,在服务器端运行Wireshark可能是个好主意。它们都位于相同的IP地址上,在套接字69(服务器)和另一个随机套接字(客户端)之间跳转数据包。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class server_v004 {
private InetAddress serverAddress;
private int serverPort;
private DatagramSocket serverSocket;
private static final ExecutorService exec = Executors.newFixedThreadPool(10);
public void startServer()
{
try {
String serverIpAddress = "192.168.1.32";
InetAddress echoServerIP = InetAddress.getByName(serverIpAddress);
serverSocket = new DatagramSocket(serverPort, echoServerIP);
System.out.println("TftpServer on port " + serverSocket.getLocalPort());
while(true) {
byte[] buf = new byte[1472];
DatagramPacket p = new DatagramPacket(buf, 1472);
System.out.println("waiting for connection ....");
serverSocket.receive(p);
server_v004ServerWorker worker = new server_v004ServerWorker(p);
exec.execute(worker);
}
}
catch(Exception e) {
System.err.println("Exception: " + e);
}
serverSocket.close();
return;
}
public static void main(String[] args) {
server_v004 tftpServer = new server_v004();
//tftpServer.checkArgs(args);
try{
tftpServer.parseArgsAndInit(args);
tftpServer.startServer();
}
catch(Exception e){
e.printStackTrace();
}
}
private void checkArgs(String[] args){
if(args.length <0) { //<1 //<2
System.out.println("Usage: TftpServer"); //server_port server_ip
System.exit(0);
}
}
private void parseArgsAndInit(String[] args) throws Exception{
//serverAddress = InetAddress.getByName(args[0]);
serverPort = 12345; //Integer.parseInt(args[1]);
}
}
class server_v004ServerWorker implements Runnable
{
//use to store RRQ request
private DatagramPacket req;
//client address who sent the RRQ request
private SocketAddress clientAddress;
//socket used to send the file data packets to client
private DatagramSocket sendfileSocket;
//byte buffer to store the file data
private byte[] dataBuffer = new byte[TftpUtil.DATA_BUFFER_SIZE];
//the first block sequence
private byte currentBlockSeq = 1;
//use to retrieve the ack packet, only two bytes long
private DatagramPacket ackDP = new DatagramPacket(new byte[2], 2);
private int TIME_OUT = 1000; //1 second
public void run(){
try{
sendfileSocket = new DatagramSocket(69);
System.out.println("TftpServer sending a file on port " + sendfileSocket.getLocalPort());
byte pType = TftpUtil.checkPacketType(req);
clientAddress = req.getSocketAddress();
//checking if the first packet from client is a RRQ packet
if(pType == TftpUtil.RRQ){
String filename = getFileName(req);
System.out.println("Requested file name:" + filename);
//if the file doesn't exist, send ERROR packet and close socket
if(!(new File(filename)).exists()) {
DatagramPacket errorDP = TftpUtil.packErrorPacket(filename);
errorDP.setSocketAddress(clientAddress);
sendfileSocket.send(errorDP);
}
else{
//the file does exist, send file
sendfile(filename);
}
}// end if
}catch(Exception e){
e.printStackTrace();
}
sendfileSocket.close();
return;
}
private void sendfile(String filename) throws Exception{
FileInputStream fileInput = new FileInputStream(filename);
while(true){
int rec = fileInput.read(dataBuffer);
//the file size is a multiple of 512, send empty packet
if(rec == -1){
sendDataPacket(new byte[0],0);
System.out.println("The last packet [0 byte in size]:#"+currentBlockSeq);
break;
}
//send a file data packet
boolean successed = sendDataPacket(dataBuffer,rec);
//tried five times
if (!successed) {
System.out.println("Tried five times, give up");
System.exit(0);
}
// the last packet (the file size if not a multiple of 512)
if (rec < 512 && rec > 0 ) {
System.out.println("The last packet ["+rec+" bytes in size]:#"+currentBlockSeq);
break;
}
currentBlockSeq++;
}//while
fileInput.close();
}
//
private boolean sendDataPacket(byte[] databuffer,int length) throws Exception{
int resendCount = 0;
DatagramPacket dataPacket = packFileDataPacket(databuffer,length);
//try five times
while(resendCount < TftpUtil.MAX_RESEND){
try{
sendfileSocket.send(dataPacket);
sendfileSocket.setSoTimeout(TIME_OUT);
System.out.println("sent data block #"+currentBlockSeq+", waiting for ack #" + currentBlockSeq);
//ack arrives
sendfileSocket.receive(ackDP);
byte ackedBlockseq = TftpUtil.extractACKNumber(ackDP);
System.out.println("received ack #" + ackedBlockseq);
if(ackedBlockseq != currentBlockSeq) {
//the acked block seq is not the seq of block sent
//ignore this ack and resend
resendCount++;
continue;
}
//this data packet has been acked, return
return true;
}//end of try
catch(SocketTimeoutException ste){
resendCount++;
System.out.println("timeout #" + resendCount );
}
}//end of while
return false;
}
private DatagramPacket packFileDataPacket(byte[] dataBuffer, int length){
int packetLength = 2 + length;//type (1) + block seq (1) + data length
ByteBuffer byteBuffer = ByteBuffer.allocate(packetLength);
byteBuffer.put(TftpUtil.DATA);//type
byteBuffer.put(currentBlockSeq);//block seq
byteBuffer.put(dataBuffer,0,length);//data
DatagramPacket dataPacket = new DatagramPacket(byteBuffer.array(), packetLength);
dataPacket.setSocketAddress(clientAddress);
return dataPacket;
}
private String getFileName(DatagramPacket dataDP){
byte[] data = dataDP.getData();
int dataLength = dataDP.getLength();
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength-1);
//remove the packet type (RRQ)
byteBuffer.put(data,1,dataLength-1);
return new String(byteBuffer.array());
}
public server_v004ServerWorker(DatagramPacket req)
{
this.req = req;
}
}
import java.net.DatagramPacket;
import java.nio.ByteBuffer;
public class TftpUtil {
//read request packet
public static final byte RRQ = 1;
//data packet
public static final byte DATA = 2;
//ack packet
public static final byte ACK = 3;
//error packet
public static final byte ERROR = 4;
//the maximum number of resent
public static final int MAX_RESEND = 5;
//data buffer size: 512
public static int DATA_BUFFER_SIZE = 512;
//packet buffer size: 2 bytes header + 512 bytes file data;
public static int PACKET_BUFFER_SIZE = DATA_BUFFER_SIZE + 2;
//return the type (RRQ, DATA, ACK or ERROR) of a packet
public static byte checkPacketType(DatagramPacket dataDP){
byte[] payload = dataDP.getData();
return payload[0];
}
//return a RRQ packet
public static DatagramPacket packRRQDatagramPacket(byte[] filename) throws Exception{
return packDatagramPacket(RRQ, filename);
}
//return a "file not found" error packet
public static DatagramPacket packErrorPacket(String filename) throws Exception{
String errorMessage = filename + " not found";
return packDatagramPacket(ERROR, errorMessage.getBytes());
}
/*
* utility method that wrap a packet type, data into a DatagramPacket
*/
private static DatagramPacket packDatagramPacket(byte type, byte[] payload) throws Exception{
int dataLength = 1 + payload.length;
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength);
byteBuffer.put(type);
byteBuffer.put(payload);
return new DatagramPacket(byteBuffer.array(), dataLength);
}
//return the ack number of a ACK packet
public static byte extractACKNumber(DatagramPacket ackDP){
byte[] payload = ackDP.getData();
return payload[1];
}
//print the string content of a ERROR packet
public static void printErrorString(DatagramPacket p){
byte[] data = p.getData();
int dataLength = p.getLength();
ByteBuffer byteBuffer = ByteBuffer.allocate(dataLength-1);
//ignore the packet type
byteBuffer.put(data,1, dataLength-1);
System.out.print(new String(byteBuffer.array()));
}
//return the block sequence of a data packet
public static byte extractBlockSeq(DatagramPacket dataDP){
byte[] payload = dataDP.getData();
if(payload.length <=1) return -1; //-1: no block sequence in data
int type = payload[0];
if(type == DATA){
return payload[1];
}
return -1; //-1: not a data packet
}
}