자바 소켓(Socket)

ednadev·2020년 7월 16일
0

자바

목록 보기
22/22
post-thumbnail

네트워킹(Networking)
두 대 이상의 컴퓨터를 케이블로 연결하여 네트워크(network)를 구성하는 것을 말한다. 자바에서 제공하는 java.net 패키지를 사용하면 이러한 네트워크 애플리케이션의 데이터 통신 부분을 쉽게 작성할 수 있다.

클라이언트(client)와 서버(server)
컴퓨터 간의 관계를 역할로 구분하는 개념이다.
서버(server)는 서비스를 제공하고, 클라이언트(client)는 서비스를 사용한다.

IP 주소
컴퓨터(host)를 구별하는데 사용되는 고유한 값으로 인터넷에 연결된 모든 컴퓨터는 IP 주소를 갖는다.

URL(Uniform Resource Locator)

프로토콜://호스트명:포트번호/경로명/파일명?쿼리스트링#참조

인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소를 표현하기 위한 것이다.

소켓(socket)

ftp, http, ... 등 여러 가지 통신이 있는데 그중 프로세스 간의 통신에 사용되는 양쪽 끝단(endpoint)을 의미하는 것이 '소켓'이다.

socket은 임의로 지정한 포트를 사용하고 이후 나오는 jdbc:mysql은 3306 포트이다. 데이터는 stream을 통해 날아간다.

Server

  1. 서버 소켓 생성
ServerSocket server = new ServerSocket(port);

소켓 통신에서 포트는 1~65535 중에 1~1024는 예약되어 있으므로 이 외에서 사용한다.

  1. client의 접속을 맞이한다.
Socket s = server.accept();

Client

  • Socket 생성
Socket s = new Socket("server ip", port)

소켓을 생성하는 순간 (서버 주소가 들어가므로) 서버에 접속한다!
매핑 되도록 포트를 똑같이 가져야 한다.

Step 1

Server

클라이언트가 보낸 메시지를 받아서 자신의 콘솔 창에 받은 메시지를 출력 (데이터를 받는 입장, 처리한 결과를 보내고)

로직

  1. ServerSocket 생성 (port : 임의 지정)
  2. 클라이언트가 서버에 접속하면 aceept로 받아서 Socket을 하나 리턴
  3. 소켓으로부터 스트림 리턴
public class ChattServer {
    ServerSocket server;
    Socket s;
    BufferedReader br;
	
    public void go() {
	try {
	    server = new ServerSocket(60000);
	    System.out.println("Server Ready........");
			
	    s = server.accept();
	    System.out.println("Client Socket...Returning...");
			
            // System.in은 Local이었다면 소켓으로부터 리턴받은 스트림은 외부
	    br = new BufferedReader(new InputStreamReader(s.getInputStream())); 
			
            //클라이언트가 던지는 걸 읽는다
	    String line = null;
	    while((line = br.readLine())!=null) {
		System.out.println("Client가 보낸 메세지 " + line);
	    }
	    br.close();
	}catch(Exception e) {
	    System.out.println("Client와의 연결이 끊어졌습니다..");
	}
    }
    
    public static void main(String[] args) {
	ChattServer cs = new ChattServer();
	cs.go();
    }
}

Client

키보드로 입력받은 데이터를 읽어서 서버로 출력 (데이터를 보내는 입장, 처리한 결과를 받는다)

로직

  1. 소켓 생성
  2. 스트림
public class ChattClient {
    Socket s;
    BufferedReader br;
    PrintWriter pw;
	
    public void go() {
	try {
	    s = new Socket("127.0.0.1", 60000);
	    System.out.println("Client Socket Creating....^^");
			
	    br = new BufferedReader(new InputStreamReader(System.in));
	    pw = new PrintWriter(s.getOutputStream(), true); //auto flush
			
	    System.out.println("Client stream Creating....^^");
			
	    String line = "";
	    while((line=br.readLine())!=null) {
		pw.println(line);
	    }
	}catch(Exception e) {
	    System.out.println("서버와의 연결에 실패했습니다...");
	}
    }
	
    public static void main(String[] args) {
	ChattClient cc = new ChattClient();
	cc.go();
    }
}
  • Client : 서버에 메시지를 보내면
  • Server : Client에서 보낸 메시지를 받는다

Step 2

Server

클라이언트가 보낸 메시지를 받아서 다시 클라이언트에게 받은 메시지를 보낸다.

로직

  1. ServerSocket 생성 (port : 임의 지정)
  2. 클라이언트가 서버에 접속하면 aceept로 받아서 Socket을 하나 리턴
  3. 소켓으로부터 스트림 리턴
public class ChattServer {
    ServerSocket server;
    Socket s;
    BufferedReader br;
    PrintWriter pw;  //추가
	
    public void go() {
	try {
	    server = new ServerSocket(60000);
	    System.out.println("Server Ready........");
			
	    s = server.accept();
	    System.out.println(s.getInetAddress() + " 님이 접속하셨습니다..");

	    br = new BufferedReader(new InputStreamReader(s.getInputStream())); 
	    pw = new PrintWriter(s.getOutputStream(), true);  //추가
			
	    String line = null;
	    while((line = br.readLine())!=null) {
		pw.println(line);  //클라이언트에게 보낸다
	    }
	    br.close();
	}catch(Exception e) {
	    System.out.println("Client와의 연결이 끊어졌습니다..");
	}
    }
	
    public static void main(String[] args) {
	ChattServer cs = new ChattServer();
	cs.go();
    }
}

Client

키보드로 입력받은 데이터를 읽어서 서버로 보낸다.
다시 서버가 보낸 메시지를 받아서 클라이언트 자신의 콘솔 창에 출력한다.

로직

  1. 소켓 생성
  2. 스트림
public class ChattClient {
    Socket s;
    BufferedReader br, br1; //추가
    PrintWriter pw;
	
    public void go() {
	try {
	    s = new Socket("127.0.0.1", 60000); 
	    System.out.println("Client Socket Creating....^^");
			
	    br = new BufferedReader(new InputStreamReader(System.in));
	    pw = new PrintWriter(s.getOutputStream(), true);
	    br1 = new BufferedReader(new InputStreamReader(s.getInputStream()));  //추가
			
	    System.out.println("Client stream Creating....^^");
			
	    while(true) {
		String line = br.readLine(); //키보드로 입력받은 데이타 읽어서..
		pw.println(line); //서버로 간다...
				
		String serverMsg = br1.readLine(); //서버가 보낸 메세지
		System.out.println("서버가 보낸 메세지 : " + serverMsg);
	    }
	}catch(Exception e) {
	    System.out.println("서버와의 연결에 실패했습니다...");
	}
    }

    public static void main(String[] args) {
	ChattClient cc = new ChattClient();
	cc.go();
    }
}
  • Server : 클라이언트의 접속을 확인한다.
  • Client : 서버에 보낸 메시지를 출력한다.

Step 3

여러 개의 Client 프로세스가 Server에 간다
process의 필드와 thread의 필드를 나누고 process 적인 기능만 뽑아낸다.
thread는 run 밖에 없다.

  1. Server에 ServerSocket(ReceptionDesk)을 먼저 만든다.
    --> 모두 걸쳐가야 하는 곳
  2. ServerSocket에서 accept()로 Client를 맞이한다.
  3. Socket이 만들어지고 Socket으로부터 Stream을 만든다.
    --> thread가 해야 함
  4. Socket이 리턴되자마자 생성해야 하는 것.. thread가 가져가야 함
  5. thread가 스트림을 가지면서 thread가 메시지 주거니 받거니를 해야 함
  6. 쓰레드 객체가 점점 늘어나는데.. ArrayList로 관리.. 생성할 때는 add, 빠져나갈 때는 나갔다고 remove

Client도 쓰레드가 필요하다

  • 메시지를 작성하는데 동시에 다른 데서 쓴 메시지를 받을 수 있다.
  • 내가 데이터를 보내는 동안 받는 쓰레드를 만들어야 한다.

내가 쓰는 건 그대로, 서버가 던지는 데이터만 전담하는 쓰레드를 만들면 된다.

Server

public class ChattServer {
    ServerSocket server;
    Socket s;
    ArrayList<ChattThread> list; // BufferedReader, PrintWriter - Thread에서
	
    public ChattServer() {
	list = new ArrayList<>();
    }
	
    public void broadcast(String message) { 
	for(ChattThread t : list) {
	    t.sendMessage(message);
	}
    }
	
    public void go() {
	try {
	    server = new ServerSocket(60000);
	    System.out.println("Server Ready......");
			
            // Client 여러명을 받아서 쓰레드 ArrayList로 관리
	    while(true) {//윙윙~~
		s = server.accept();
		ChattThread ct = new ChattThread(s, this);
		list.add(ct);
		ct.start(); //run
	    }
	}catch(Exception e) {
		
	}
    }
	
    public static void main(String[] args) {
	ChattServer cs = new ChattServer();
	cs.go();
    }
}

class ChattThread extends Thread{
    Socket s;
    BufferedReader br;
    PrintWriter pw;
    ChattServer chattServer; 
	
    ChattThread(Socket s, ChattServer chattServer) {
	this.s = s;
	this.chattServer = chattServer;
	System.out.println(s.getInetAddress() + " 님이 접속하셨습니다...");
	chattServer.broadcast(s.getInetAddress()+" 님이 채팅방에 들어오셨습니다.");
    }
	
    public void sendMessage(String str) {
	pw.println(str);
    }
	
    public void run() {
	try {
	    br = new BufferedReader(new InputStreamReader(s.getInputStream()));
	    pw = new PrintWriter(s.getOutputStream(), true);
			
	    while(true) {
		String line = br.readLine();
		chattServer.broadcast(line);
	    }
	}catch(IOException e) {
	    //연결이 끊어졌을때 이곳으로 이동한다..
	    System.out.println(s.getInetAddress() + " 님이 접속을 끊으셨습니다..");
	    chattServer.broadcast(s.getInetAddress() + " 님이 채팅방을 나가셨습니다..");
	    chattServer.list.remove(this); //this는 본인 자신! Thread
	}
    }
}

Client

public class ChattClient {
    Socket s;
    BufferedReader br;
    PrintWriter pw;
	
    public void go() {
	try {
	    s = new Socket("127.0.0.1", 60000); 
	    System.out.println("Client Socket Creating....^^");
			
	    br = new BufferedReader(new InputStreamReader(System.in));
	    pw = new PrintWriter(s.getOutputStream(), true); //auto flush
			
	    //추가
	    ClientThread ct = new ClientThread(s);
	    ct.start(); //---> run()
			
	    while(true) {
		String line = br.readLine(); //키보드로 입력받은 데이타 읽어서..
		pw.println(line); //서버로 간다...
	    }
	}catch(Exception e) {
	    System.out.println("서버와의 연결에 실패했습니다...");
	}
    }
	
    public static void main(String[] args) {
	ChattClient cc = new ChattClient();
	cc.go();
    }
}

class ClientThread extends Thread { //서버가 보낸 데이타만 전담으로 읽어들이는 쓰레드
    Socket s;
    BufferedReader br2;
    String str;
	
    ClientThread(Socket s) {
	this.s = s;
    }
	
    public void run() {
	try {
	    br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
		while(true) {
		    str = br2.readLine();
		    System.out.println("서버메세지 : " + str);
		}
	} catch(Exception e) {
			
	}
    }
}

관심 있을 만한 포스트

0개의 댓글