안녕하세요. 몇일간 고민하고 구글링해도 답을 찾기 어려워 이렇게 질문 글을 남깁니다.
PC 와 안드로이드 폰 간의 소켓통신을 하려고 합니다.
간단한 FLOW 는 아래와 같습니다.
휴대폰 (Client), PC ( Server) 일 경우
클라이언트에서 먼저 파일 전송 ---> 서버에서 파일 수신 ---> 서버에서 잘 받았다고 클라이언트에 메세지 보냄 ---> 클라이언트에서 서버의 메세지 수신
근데 마지막 과정인 "클라이언트에서 서버의 메세지 수신" 부분이 안되네요.
그냥 간단히 메세지만 주고 받기는 가능합니다. 그런데 파일 전송하는 부분이 들어가면
서버쪽에서 잘 받았다는 메세지를 클라이언트(안드로이드폰) 에서 읽지를 못하네요.
소켓통신에 대해 초보라서 3~4일 헤매도 답을 못찾겠습니다.
고수님들 조언 부탁드립니다. __)
< 참고로 둘다 스레드로 구현되어 있습니다.
서버쪽은 accept 함수에서 응답이 오면 스레드를 생성하게 되어 있고
클라이언트 쪽은 브로드 캐스트 안에서 스레드를 생성하여 동작하도록 되어 있습니다. >
혹시나 해서 풀소스 첨부합니다.
안드로이드 외장디스크에 "SMART_WIDGET" 폴더에 "GPS_LogFile.txt" 파일 있어야 하고
ServerThread.java 에서 파일이 저장될 경로를 수정해서 테스트 해보시면 됩니다.
==============================================================================================
[ 서버 ]
public class ServerThread extends Thread {
private static String FOLDER_PATH = "C:/Users/MJ/workspace/SmartWidget_Server/logFile";
private static String FILE_PATH = "GPS_LogFile.txt";
Socket socket;
BufferedReader br;
BufferedWriter bw;
BufferedOutputStream bo;
FileOutputStream output;
PrintWriter pr;
File file;
ServerThread(Socket _socket) throws IOException {
socket = _socket;
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
file = new File(FOLDER_PATH + "/" + FILE_PATH);
// 파일을 쓰기 위해 outputstream 을 가져온다.
output = new FileOutputStream(file);
}// ServerThread
@Override
public void run() {
try {
String str = br.readLine();
System.out.println("클라이언트의 메세지 : " + str);
} catch (IOException e1) {
e1.printStackTrace();
}
byte[] buf = new byte[1024];
// 클라이언트에서 받은 GPS 값을 저장한다.
try {
// while ( socket.getInputStream().read(buf) > 0 ) {
// output.write(buf);
// output.flush();
// }
String line = null;
while ( (line = br.readLine()) != null ){
System.out.println("str : " + line);
}// while
output.close();
} catch (IOException e) {
e.printStackTrace();
}// while
System.out.println("클라이언트로 보내는 메세지 : 잘 받았어요!!");
pr.println("잘 받았어요!!");
pr.flush();
System.out.println("--- end ! ");
try {
pr.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
==============================================================================================
[ 클라이언트 ]
public class UploadGPS implements Runnable {
private static final Boolean PLUG = true; // 디버그 라인 켜고 끄는 플러그인
private static final String TAG = "SMART";
private static final String FOLDER_NAME = "SMART_WIDGET";
private static final String FILE_NAME = "GPS_LogFile.txt";
private String ip;
private int port;
private Socket socket;
FileInputStream fileStream;
BufferedReader br;
BufferedOutputStream bw;
PrintWriter pr;
DataInputStream dis;
DataOutputStream dos;
private static File sdcard;
private static File dbpath;
UploadGPS(String ip, int port) {
super();
this.ip = ip;
this.port = port;
}
public void run() {
if ( ip == null || port == 0 ) {
System.out.println("[Client] Can't find ip or port value!");
System.exit(-1);
}
// 외장 메모리 path 만들기
sdcard = Environment.getExternalStorageDirectory();
dbpath = new File(sdcard.getAbsolutePath() + File.separator + FOLDER_NAME);
if ( !dbpath.exists() ){
if ( PLUG ) Log.w(TAG, "There's no Folder." + dbpath.getAbsolutePath());
return; // 폴더가 없으면 종료
}
// 파일 스트림을 연다.
try {
fileStream = new FileInputStream(new File(dbpath + File.separator + FILE_NAME));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// socket 생성
try {
socket = new Socket(ip, port);
} catch (UnknownHostException e) {
Log.e("TAG", "소켓을 받아오지 못했습니다.");
e.printStackTrace();
} catch (IOException e) {
Log.e("TAG", "소켓을 받아오지 못했습니다2.");
e.printStackTrace();
}
// 파일 이외에 데이터를 주고 받기 위해 필요한 스트림들.
try {
pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e2) {
e2.printStackTrace();
}
// 먼저 메세지 던진다.
pr.println("hey hello server!");
pr.flush();
Log.w("TAG", "to client : hey hello server!");
DataOutputStream dos = null;
try {
dos = new DataOutputStream(socket.getOutputStream());
} catch (IOException e1) {
e1.printStackTrace();
}
// 파일에서부터 값을 받아올 수 있도록 파일 stream 만든다.
dis = new DataInputStream(fileStream);
byte[] buf = new byte[1024];
// 파일에서 값을 가져와서 서버로 보낸다.
try {
while ( dis.read(buf) > 0 ) {
dos.write(buf);
dos.flush(); // 실제로 전송하는 부분
}// while
dos.close(); // outputStream
dis.close(); // filestream
} catch (IOException e) {
e.printStackTrace();
}
// 서버로부터 받는 메세지
String return_msg = null;
try {
return_msg = br.readLine();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Log.e("TAG", "From Server : " + return_msg);
try {
br.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}// UploadGPS
답변 감사합니다.
근데 dis 는 filestream 인데 stream 의 종류가 다르면 상관없지 않나요?
스트림의 종류에 상관없이 input 되는 스트림은 어떤 거라도 닫으면 안되는건가요?? 으흠.
그리고 여기서 dis 는 안드로이드 폰 상의 filestream 이라서 서버로부터의 inputStream 즉, br 변수는 아직 닫지 않았습니다.
말씀하신대로 close() 주석처리 해봐도 안되는군요.ㅜㅜ
return_msg 에 null 값만 찍힙니다.
제 댓글을 다시 볼지 모르겠는데 아시면 답변 좀 부탁드려요. 흑.
while ( dis.read(buf) > 0 ) {
dos.write(buf);
dos.flush(); // 실제로 전송하는 부분
}// while
dos.close(); // outputStream
dis.close(); // filestream <- InputStream 을 닫아버려서 더이상 데이터를 받지 못함..
} catch (IOException e) {
e.printStackTrace();
}
// 서버로부터 받는 메세지
String return_msg = null;
try {
return_msg = br.readLine(); // 이미 Input Stream 은 닫혀있음...
하나의 스트림을 여러개의 변수에서 사용했을 때 하나를 close 하면 모두 사용하지 못하는걸로 알고있어요.
여러개의 변수로 사용할수있을지언정 스트림 자체는 하나니까요
그리고 소켓 구성이 아슬아슬하게되어있네요^^;;
아래의 강좌보시구 한번 다시 코드봐보세요. 이것도 PC-스마트폰 통신이거든요ㅎㅎ
http://www.tipssoft.com/bulletin/tb.php/FAQ/931