네트워크

소켓 프로그래밍(TCP/IP socket)[JAVA]

솔트리 2022. 3. 31. 20:54
TCP UDP
연결형 비연결형
신뢰성 비신뢰성

Q) TCP 는 왜 신뢰성일까..?

A) 패킷 유실시에 다시 재전송을 하기 때문이다. 

 

 

Q) 소켓 이란..?

A socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to.

+ endpoint : ip와 port 번호의 조합

 

:: 소켓은 서로 다른 프로그램(ex> 서버와 클라이언트)의 양방향 커뮤니케이션을 위한 도구. 소켓은 하나의 포트 번호에 종속되어 있다(클라이언트에서 보내는 데이터를 올바른 어플리케이션에 보내기위해)

 

 

소켓 API 실행 흐름

https://www.geeksforgeeks.org/tcp-server-client-implementation-in-c/

  1. TCP 소켓 생성
  2. 소켓을 서버 주소에 바인드 한다.
  3. 서버 소켓이 클라이언트의 접근을 기다린다.
  4. 클라이언트가 접근하면 server가 accept() 수락함으로써 서버와 클라이언트가 데이터를 주고 받을 준비가 된다. 

=> 

  1. create
  2. connect
  3. send/recv
  4. close 

를 처리하는 로직이 필요하다.

 

자바로 소켓 프로그래밍

자바로 소켓 프로그래밍을 해보려면 위의 create, connect, send/recv, close 의 로직을 만들어줄 자바 메소드와 클래스를 알아야한다.

 

create : java.net.ServerSocket 클래스를 이용해서 소켓을 생성한다.

  • ServerSocket(int port)  :  주어진 포트를 사용하는 서버 소켓을 생성한다.

connect : java.net.Socket 클래스를 이용해서 서버 주소와 특정 포트에 연결한다.

  • Socket(innetAddress address, int port)
  • Socket(String host, int port)

send/recv : BufferedReader와 PrintWriter을 이용해서 문자열을 send/recv 한다.

 

 

소켓을 이용해서 서버에 특정 영어 문자열을 보내면 대문자는 소문자로, 소문자는 대문자를 클라이언트에 보내는 프로그램을 짜봤다.

소스코드

- TCPServer.java

package socketProgramming;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class TCPServer {
	
	
	public final static int SERVER_PORT=9999;	
	
   public static void main(String arg[]) throws IOException
    {
        Socket client_socket = null;                //Client와 통신하기 위한 Socket
        ServerSocket server_socket = null;  //서버 생성을 위한 ServerSocket - 송수신을 위한 소켓을 생성함
        BufferedReader in = null;            //Client로부터 데이터를 읽어들이기 위한 입력스트림
        PrintWriter out = null;                //Client로 데이터를 내보내기 위한 출력 스트림
        
        try{
            server_socket = new ServerSocket(SERVER_PORT);
        }catch(IOException e)
        {
        	e.printStackTrace();
        }
        
      
		
		try {
			
			System.out.println("[[[[SERVER]]]]");
			System.out.println("연결을 기다리는 중 . . .");
			// accept 메소드 : 클라이언트가 들어오는 것을 대기하는 역할
			// 클라이언트가 해당 포트로 연결을 시도한다면, accept 메소드는 대기를 풀고, 클라이언트와 연결시키는
			// socket 클래스를 생성(client_socket)하여 반환하게 된다. 
			// client_socket : 클라이언트랑 1:1 연결된 소켓 - client_socket으로 클라이언트와 통신한다.
				
			client_socket = server_socket.accept();   
			
			// 소켓으로부터 데이터 읽어옴 
			in = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
			out = new PrintWriter(new OutputStreamWriter(client_socket.getOutputStream())); //출력스트림 생성
					
			while(true) {
				
				String str = null;
				str = in.readLine();                //Client로부터 데이터를 읽어옴
				
				System.out.println("Client로 부터 온 메세지 : " + str);
				
				
				if(str.equalsIgnoreCase("quit")) { // 클라이언트가 quit을 입력하면 종료
					System.out.println("통신 종료 ===========");
					break;
				}
				
				StringBuilder res = new StringBuilder();
				
				for(int i = 0; i<str.length();i++) {
					if(str.charAt(i)<'a') { // 대문자라면 소문자로 바꿔줌 + 32
						res.append((char)(str.charAt(i)+32));
					}else {
						res.append((char)(str.charAt(i)-32));
					}
				}
				
				
				out.println(res.toString());
				
				// 버퍼 비움
				out.flush();
			}
			
		}catch(IOException e){
			e.printStackTrace();
		}finally {
			// 자원반납
			if(in!=null) in.close();
			if(out!=null) 	out.close();
			if(client_socket!=null) client_socket.close();
			if(server_socket!=null) server_socket.close();
		}
        
    }
}

 

- TCPClient.java

package socketProgramming;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class TCPClient{
	
	public final static int SERVER_PORT=9999;	
	
    public static void main(String[] arg) throws IOException
    {
        Socket socket = null;            //Server와 통신하기 위한 Socket
        BufferedReader in = null;        //Server로부터 데이터를 읽어들이기 위한 입력스트림
        BufferedReader in2 = null;        //키보드로부터 읽어들이기 위한 입력스트림
        PrintWriter out = null;            //서버로 내보내기 위한 출력 스트림
        InetAddress ia = null;
        	
    	try {
    		
    			
            ia = InetAddress.getByName("127.0.0.1");    //서버로 접속 ( local 이라서 127.0.0.1)
            socket = new Socket(ia, SERVER_PORT);
            
            System.out.println("[[[[CLIENT]]]]");
            
            System.out.println("연결 성공");
            System.out.println(socket.toString()); // 소켓 정보 출력
			
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            in2 = new BufferedReader(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
    			
            while(true) {
            	
    			System.out.print("서버로 보낼 메세지 : ");
    			String data = in2.readLine();            //키보드로부터 입력
    			out.println(data);    //서버로 데이터 전송
    			out.flush();	// 버퍼 비움
    			
    			if(data.equalsIgnoreCase("quit")){
    				System.out.println("통신 종료 ===========");
    				break;
    			}
    			
    			String str2 = in.readLine();            //서버로부터 되돌아오는 데이터 읽어들임
    			
    			System.out.println("서버로부터 되돌아온 메세지(lowerCase<->upperCase) : " + str2);
    			
    		}
    		
    	}catch(IOException e) {
    		e.printStackTrace();
    	}finally {
    		// 자원반납
			if(in!=null) in.close();
			if(in2!=null) in2.close();
			if(out!=null)  out.close();
			if(socket!=null) socket.close();
			
			return;
    	}
    }
    
    
}

결과

 

참조: https://reakwon.tistory.com/168

https://lktprogrammer.tistory.com/62

https://m.blog.naver.com/highkrs/220840680504

https://cbw1030.tistory.com/52