2013-01-06 4 views
0

서버와 클라이언트가 서버에서 클라이언트로 파일을 전송하는 코드를 작성하여 매력적으로 작동했습니다. 그러나 나는 몇 가지 질문이있다. GUI에서이 코드를 작성하고 폴더의 모든 파일을 나열하려고하지만 클라이언트가 제공하는 파일 목록을 본 후 원하는 파일을 선택하게하려면 어떻게해야합니까 (어떻게 문자열을 보낼 수 있습니까). 서버가 파일을 선택하려면)?서버에 요청 보내기 java

서버 코드

import java.io.*; 
import java.net.*; 



class TCPServer { 

    public static void listfile(){ 

    File folder = new File("c:/"); 
    File[] listOfFiles = folder.listFiles(); 

    for (int i = 0; i < listOfFiles.length; i++) { 
     if (listOfFiles[i].isFile()) { 
     System.out.println("File " + listOfFiles[i].getName()); 
     } else if (listOfFiles[i].isDirectory()) { 
     System.out.println("Directory " + listOfFiles[i].getName()); 
     } 
    } 
    } 


    public static void main(String args[]) { 

     listfile(); 

     while (true) { 
      ServerSocket welcomeSocket = null; 
      Socket connectionSocket = null; 
      BufferedOutputStream outToClient = null; 

      try { 
       welcomeSocket = new ServerSocket(3248); 
       connectionSocket = welcomeSocket.accept(); 
       outToClient = new BufferedOutputStream(connectionSocket.getOutputStream()); 
      } catch (IOException ex) { 
       // Do exception handling 
      } 


      if (outToClient != null) { 

       String FileName = "carexception.java"; 

       File myFile = new File("C:\\"+FileName); 

       byte[] mybytearray = new byte[(int) myFile.length()]; 

       FileInputStream fis = null; 

       try { 
        fis = new FileInputStream(myFile); 
       } catch (FileNotFoundException ex) { 
        // Do exception handling 
       } 
       BufferedInputStream bis = new BufferedInputStream(fis); 

       try { 
        bis.read(mybytearray, 0, mybytearray.length); 
        outToClient.write(mybytearray, 0, mybytearray.length); 
        outToClient.flush(); 
        outToClient.close(); 
        connectionSocket.close(); 

        // File sent, exit the main method 
        return; 
       } catch (IOException ex) { 
        // Do exception handling 
       } 
      } 

     } 
    } 
} 

import java.io.*; 
import java.net.*; 
import java.util.*; 

class TCPClient { 

    public static void main(String args[]) { 
     Scanner s = new Scanner(System.in); 
     byte[] aByte = new byte[1]; 
     int bytesRead; 

     Socket clientSocket = null; 
     InputStream is = null; 

     try { 
      clientSocket = new Socket("127.0.0.1", 3248); 
      is = clientSocket.getInputStream(); 
     } catch (IOException ex) { 
      // Do exception handling 
     } 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

     if (is != null) { 

      FileOutputStream fos = null; 
      BufferedOutputStream bos = null; 
      try { 
       fos = new FileOutputStream("E:\\sss.java"); 
       bos = new BufferedOutputStream(fos); 
       bytesRead = is.read(aByte, 0, aByte.length); 

       do { 
         baos.write(aByte); 
         bytesRead = is.read(aByte); 
       } while (bytesRead != -1); 

       bos.write(baos.toByteArray()); 
       bos.flush(); 
       bos.close(); 
       clientSocket.close(); 
      } catch (IOException ex) { 
       // Do exception handling 
      } 
     } 
    } 
} 
+0

btw 누군가 elses 코드를 복사하기 만하면 [소스를 참조] (http://stackoverflow.com/a/4687706/116249)해야합니다. – Patrick

답변

0

당신이 배열을 만드는 시도, 그래서 각 파일이 그것을 자신의 인덱스를 ...이 클라이언트 코드 클라이언트는, 그가 원하는 파일을 선택하면 특정 배열 인덱스에서 파일을 반환하십시오.

~ btw 배열을 직렬화하여 클라이언트에게 보낼 수 있습니다.

+0

일할 수는 있지만 파일 목록을 표시하고 클라이언트가 원하는 파일을 입력하여 답장을 보내려면 어떻게해야합니까? –

+0

@RaymondBouChaaya 이해할 수있는 방법으로 이러한 GUI 양식을 만드는 방법을 묻습니다. 파일 이름 중 하나를 선택할 수 있습니까? –

+0

프로그램이 실행될 때 클라이언트가 availble 파일 목록에서 파일을 선택할 수있게하려면 –

1

어떻게 파일을 확인 하시겠습니까? 이름으로! 나는 서버가 명령을 받아들이고 응답으로 응답한다고 생각한다. CMD_NAME, arg1, arg2, ... 인수는 명령에 따라 2 진일 수 있습니다. CMD_NAME에서 서버는 원하는 것을 구별합니다 (파일을 수락하거나 제공함).

한 가지 유형의 요청 만 수락하는 데 문제가 있습니다. 서버에서 다른 요청을 요청하려면 명령 메커니즘이 필요합니다. 서버는 하드 코딩 된 응답을 즉시 제공하는 대신 이러한 요청을 구문 분석해야합니다. 이것은 유연하게 만들 것입니다.

http://www.javamex.com/tutorials/networking/simple_server_s_side.shtml 이렇게 많은 다른 예제가 있다고 확신합니다. Java 소켓은 안정적이며 문제가 될 수 없습니다. 기본 학습을 시작하기 만하면 클라이언트와 서버간에 서로 다른 메시지를 전달하는 방법을 배우십시오. 하지만 문제는 소켓과 관련이 없습니다. 파일에서 의사 소통한다고 가정 해보십시오. 하나의 요청을 읽고 응답을 다른 것으로 작성한다고 가정 해보십시오. 어떤 메시지를 다음에 쓰나요? 이를 프로토콜이라고합니다. 간단한 것을 디자인해야합니다.

+0

코딩 방법을 설명 할 수 있습니까? –

0

ObjectOutputStream을 사용하면 ObjectwriteObject을 통해 문자열이나 다른 종류의 문자를 보낼 수 있습니다.

2

당신이 한 일을 성취하기 위해서는 몇 가지 사항을 변경해야합니다.

클라이언트가 서버에 작업을 요청하기 위해 클라이언트가 서버에 요청을 보내야한다는 의미에서 특정 프로토콜 순서로 가정 할 수 있으므로 연결이 설정되면 서버는 항상 수신 대기 상태에 있습니다. . 당신이해야

,

  1. 문자열 객체를 전송하는 방법 응답을
  2. 그림을 요청을 전송하고 수신하는 루프를 소개
  3. 브레이크까지 더 큰 바이트를 할당하지 않도록 일부를 전송 파일을 (예를 들어 4GB의 파일을 고려하면 파일 전체에 바이트 배열을 할당하는 것이 번거로울 수 있습니다.)

따라서 염두에두고 우리는 지. 1 단계는 while 루프를 사용하여 수행 할 수 있습니다. 서버가 항상 요청을 수신한다고 가정하면 서버 "요청 루프"는 다음과 같이 보일 수 있습니다.

ClientRequest request; 
while (request.getType() != RequestType.Complete) { 
    // receive new request 
    // depending on type, send response 
} 

우리는 단순히 여기에 두 개의 클래스를 추가 클라이언트에서 메시지를 캡슐화 한 ClientRequest, 및 인스턴스 파일 목록 또는 파일 내용에 대한 클라이언트가 관심을 요청 유형을 정의하는 열거 RequestType.

public enum RequestType { 
    None, Complete, RequestFileList, RequestFileContent 
} 

public class ClientRequest { 
    private RequestType type; 
    public ClientRequest() { 
     type = RequestType.None; 
    } 

    public RequestType getType() { 
     return type; 
    } 
} 

이제 이것을 소켓에 연결해야하므로 요청을 수신하고 요청을 현재 요청 인스턴스에 할당하는 방법을 추가해야합니다.

ClientRequest request = new ClientRequest(); 
while (request.getType() != RequestType.Complete) { 
    // receive new request 
    receiveRequest(clientSocket.getInputStream(), request); 
    if (request.getType() != RequestType.Complete) { 
     // pick a response 
    } 
} 

private void receiveRequest(DataInputStream socketStream, ClientRequest request) { 
    // get a type of request 
    byte type = socketStream.readByte(); 
    request.setType(RequestType.from(type)); 
    // get parameters for request, depending on type 
    if (request.getType() == RequestType.RequestFileContent) { 
     // receive file id (file name for instance, or some other id that you prefer) 
     String argument = readString(socketStream); 
     request.setArgument(argument); 
    } 
} 

ClientRequest에서 요청에 setType 방법을 바이트로 변환하는 RequestType에 from 방법을 추가하고 readString 방법. 우리는 또한 ClientRequest에 새로운 필드와 상응하는 get과 set 메소드를 추가한다.

public enum RequestType { 
    // types as before 
    ; 
    public static RequestType from(byte b) { 
     switch (b) { 
      case 1: return RequestType.Complete; 
      case 2: return RequestType.RequestFileList; 
      case 3: return RequestType.RequestFileContent; 
      default: return RequestType.None; 
     } 
    } 
} 

public class ClientRequest { 
    private String argument; 
    public void setType(RequestType value) { 
     type = value; 
    } 

    public String getArgument() { 
     return argument; 
    } 

    public void setArgument(String value) { 
     this.argument = value; 
    } 
} 

private String readString(DataInputStream socketStream) { 
    int length = socketStream.readInt(); 
    byte[] stringBytes = new byte[length]; 
    socketStream.read(stringBytes); 
    return new String(stringBytes, "UTF-8"); 
} 

이제 우리는 요청에 응답하여 다음 단계로갑니다. 스위치 케이스를 추가하고 요청 유형을 처리하기 만하면됩니다.

{ 
    // depending on type, send response 
    handleRequest(clientSocket.getOutputStream(), request); 
} 

private void handleRequest(DataOutputStream socketStream, ClientRequest request) { 
    switch (request.getType()) { 
     case RequestType.RequestFileList: { 
      String[] fileList = getFileList(getCurrentDirectory()); 
      // send response type 
      socketStream.write(ResponseType.ResponseFileList.getByte()); 
      // send number of files 
      socketStream.writeInt(fileList.length); 
      // send each string 
      for (String fileName : fileList) { 
       sendString(socketStream, fileName); 
      } 
     } 
     break; 
     case RequestType.RequestFileContent: { 
      // send response type ResponseType.ResponseFileContent 
      // send length of file so other party can determine number of bytes to receive 
      // send file contents in chunks of a fixed byte array length 
      // send last part of file contents, if length of file is not evenly divided by array chunk size 
     } 
     break; 
    } 
} 

sendString 메서드는 단순히 readString 메서드의 "역순"입니다. ResponseType

private void sendString(DataOutputStream socketStream, String value) { 
    int length = value.length(); 
    socketStream.writeInt(length); 
    byte[] stringBytes = value.getBytes("UTF-8"); 
    socketStream.write(stringBytes); 
} 

RequestType에있는 것과 유사한 값의 열거, 그래서 클라이언트는 서버가 보내는 응답의 유형을 처리 할 수 ​​있습니다.

이러한 변경 사항을 사용하면 파일 목록을 요청하고 서버가 보내는 파일의 응답을 표시 할 수 있습니다. 사용자가 수신 할 파일을 선택하면 클라이언트는 서버에 새 요청을 보내고 서버는 해당 파일 내용을 클라이언트로 보낼 수 있습니다.

클라이언트 응용 프로그램은 비슷한 ClientRequest 클래스 (이름은 ServerResponse)와 서버가 소켓 스트림에서 읽고 쓰는 데 지정된 해당 메서드를 정의해야합니다. 이것은 GUI가 가입 할 수있는 요청이나 응답이 수신 될 때를위한 리스너 패턴을 사용하여 클래스에 소켓을 캡슐화함으로써 더 추상화 될 수 있습니다.

내가 무엇인가를 명확히해야한다고 생각하면 의견을 남겨주세요. 답변을 위해 최선을 다할 것입니다.

+0

첫 번째 단계에서 당신을 잃어 버렸습니다. 원래 코드에 추가하려고 할 수 있습니까? 잃어 버렸기 때문에 모든 것을 놓을 수 있었고 매우 감사 할 것입니다. –

+0

첫 번째 단계는 어떻게됩니까? 루프 코드를 의미합니까? 연결이 설정된 후에 추가해야합니다. – Patrick

관련 문제