Daily coding

Thread 사용한 소켓 프로그래밍 예제 - client 본문

Language/Java_basic

Thread 사용한 소켓 프로그래밍 예제 - client

sunnnkim 2019. 12. 11. 21:19

Client Class 및 Thread 작성하기

 

< 순서 >


  1. 접속을 해야할 Server Ip(주소)를 설정 - Socket Adress
  2. Socket 생성
  3. 접속 connect 
  4. 통신
 

 

1. mainClass

 

- 서버와 연결할 소켓을 생성한다. 소켓에 들어갈 주소는 서버와 관련된 정보이다.

1.  연결할 서버의 IP주소

2. 연결할 서버의 Port 

 

Socket 객체를 생성할 때 파라미터에 넣어 생성해도 괜찮고,

소켓 연결에 필요한 정보를 담을 InetSocketAddress  객체를 생성하여 입력하여도 좋다.

1. Socket socket = new Socket("000.000.000.000" , portNum) ;

---> 이 경우는 생성자의 파라미터에 서버 연결 IP와 port 가 있기 때문에 connect를 통해 연결하지 않아도 연결이 된다.

2. Socket socket = new Socket();

    socket.connect("000.000.000.000" , portNum );

혹은

  InetSocketAddress sockAddr = new InetSocketAddress("000.000.000.000", 9000 );

  socket.connect(sockAddr,porNum);

----> 이 경우는 소켓이 연결될 주소 값이 비어있기 때문에 

         InetSocketAddress 객체를 생성하거나 connect 함수에 직접 주소와 포트 넘버를 써줘야 한다.

 

 

public class mainClass_Client {
	// Client
	
	public static void main(String[] args)  {
		// TODO Auto-generated method stub
		
		/*
	 	1. 접속을 해야할 Server Ip(주소)를 설정 - Socket
	 	2. Socket 생성
	 	3. 접속 connect 
	 	4. 통신
	 
	 
	 */
	
		InetSocketAddress sockAddr = new InetSocketAddress("192.168.2.31", 9000 ); 
        // (IP주소, 포트넘버)
		Socket socket = new Socket(); 
        // 단 한개인 클라이언트 소켓
        
		System.out.println("서버와 연결중...");
		// Server에 접속
		try {
			socket.connect(sockAddr, 100000 );
			// (문지기 소켓 객체, 만분의1초(현재는 10초임))
			
			InetAddress inetAddr;
			if((inetAddr = socket.getInetAddress())!= null) {
			System.out.println("서버연결 성공 : " + inetAddr);
			}else {
				System.out.println("서버 연결 실패");
			}
			
			// 전송할 데이터 만들기
			Scanner sc = new Scanner(System.in);
			
			// 문자열 받아오는 스레드 만들기
			new ReadThread(socket).start();
			
			while(true) {
			System.out.print(">> ");
			String str = sc.next();
			
			
			// thread 돌리기 위해서는 언제 받을지 모르는 Receive부터 쓴 뒤 send한다
			
			// 1. send
			PrintWriter writer = new PrintWriter(socket.getOutputStream());
			// getOutputStream --> 내보낼 데이터
			writer.println(str);	// 실질적으로 전송이 되는 문자열
			writer.flush(); 		// 끝맺음
			
		

 

- 서버와 클라이언트가 연결된 후에는 데이터를 입력받는 스레드부터 만든다.

- 접속한 다른 클라이언트로부터 언제 메세지를 받을 지 모르기 때문에 Receive 스레드부터 돌리는 것

 

* ReadThread

: ReadThread 클래스는 이렇게 구성된다.

 

- BufferedReader를 통해 클라이언트의 소켓의 InputStream에 들어간 데이터를 가져온다.

- readLine()을 통해 문자열로 데이터를 받아오고, 콘솔에 출력한다.

- Thread.sleep() 메소드는 스레드가 돌아가는 주기로, 단위는 밀리세컨즈. 

   300 정도로 맞추어 두는 것이 좋음


public class ReadThread extends Thread {
	
	Socket socket;
	
	public ReadThread(Socket socket) {
		this.socket = socket;
	}
	
	// run 함수 오버라이딩
	@Override
	public void run()  {
		// TODO Auto-generated method stub
		super.run();
		
		// receive : 받기
		try {
			while(true) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			String str;
			str = reader.readLine();
			System.out.println("서버로부터 받은 메세지 : " + str);
			
			Thread.sleep(300); // 시간은 맞춰놓는 것이 좋음 
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
										
	}
	
	
	
	
	
}

 

 

* 다시 mainClass

 

- 데이터를 받고있는 스레드가 돌아가는 동안, 스캐너를 통해 콘솔로 서버 및 다른 클라이언트에 전송할  데이터를 입력 한다.

- 보내는 것은 서버 클래스와 마찬가지로, 서버로 보낼 String 데이터에 담고 PrintWriter 객체를 이용해 소켓의 OutputStream에 넣는다.

- flush를 통해 보낸다.

- while 루프가 돌아가고 스레드와는 별개로 서버로 메세지 보내는 행위가 반복 됨.

 

 

 

 * 마지막 catch문이 실행되는 경우는 소켓과 서버의 연결이 끊어진 경우이다. 

   예외처리문을 출력하기 보다는 콘솔 / 메세지 창이 뜨도록 설정하는 것이 UI 관점에서는 더 낫다.

 

// 전송할 데이터 만들기
			Scanner sc = new Scanner(System.in);
			
			// 문자열 받아오는 스레드 만들기
			new ReadThread(socket).start();
			
			while(true) {
			System.out.print(">> ");
			String str = sc.next();
			
			
			// thread 돌리기 위해서는 언제 받을지 모르는 Receive부터 쓴 뒤 send한다
			
			// 1. send
			PrintWriter writer = new PrintWriter(socket.getOutputStream());
			// getOutputStream --> 내보낼 데이터
			writer.println(str);	// 실질적으로 전송이 되는 문자열
			writer.flush(); 		// 끝맺음
			
			}
            	
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("서버연결 시간만료!");
			System.out.println("서버 연결 실패");
		} 
	
	
		
	}

}