인터넷(Internet) : 네트워크 기능을 제공하기 위한 가상의 공간 - 네트워크 관련 약속(정보 공유)
프로토콜(Protocol) : 인터넷을 사용하기 위한 네트워크 관련 통신 규약 ex) IP, TCP, UDP
TCP(Transmission Control Protocol) : 연결형 프로토콜(연결 설정 후 통신 가능)로 신뢰할 수 있는 데이타 전송에 대한 통신규약
UDP(User Datagram Protocol) : 비연결형 프로토콜(연결 설정 없이 통신 가능)로 신뢰할 수 없는 데이타 전송에 대한 통신규약
IP Address : 인터넷을 사용하기 위해 컴퓨터에 부여하는 네트워크 식별자
Netmask 주소(Netmask Address) : 네트워크 그룹(SubNet)을 표현하기 위한 주소
도메인(Domain) : 인터넷을 사용하기 위해 네트워크 그룹 또는 호스트에게 부여하는 문자화된 네트워크 식별자
포트번호(Port Number) : 네트워크를 이용하여 데이타를 전송하기 위한 고유의 통신 경로
패킷(Packet) : 네트워크에서 데이타를 전송하기 위한 단위
방화벽(Firewall) : 네트워크를 이용한 접속 및 데이터 전송 차단 또는 허용을 위해 사용하는 시스템
InetAddress.getLocalHost() : 로컬(자기자신) 컴퓨터의 네트워크 정보가 저장된 InetAddress 객체를 반환하는 메소드
InetAddress.toString() : InetAddress 객체에 저장된 네트워크 정보를 문자열로 반환하는 메소드
InetAddress.getHostName() : InetAddress 객체에 저장된 네트워크 정보에서 HostName을 문자열로 반환하는 메소드
InetAddress.getHostAddress() : InetAddress 객체에 저장된 네트워크 정보에서 IP Address을 문자열로 반환하는 메소드
InetAddress.getByName(String host) : 전달받은 컴퓨터 이름에 대한 네트워크 정보가 저장된 InetAddress 객체를 반환하는 메소드
InetAddress.getAllByName(String host) : 전달받은 컴퓨터 이름에 대한 모든 네트워크 정보가 저장된 InetAddress 객체 배열을 반환하는 메소드
public class InetAddressApp {
public static void main(String[] args) throws UnknownHostException {
InetAddress myComputer=InetAddress.getLocalHost();
System.out.println(myComputer);//DESKTOP-Q0AEAH6/192.168.13.9
System.out.println(myComputer.getHostName());//DESKTOP-Q0AEAH6
System.out.println(myComputer.getHostAddress());//192.168.13.9
//InetAddress.getByName(String host) : InetAddress 객체를 반환
InetAddress itwill=InetAddress.getByName("www.itwill.xyz");
System.out.println("IP Address = "+itwill.getHostAddress());
//InetAddress.getAllByName(String host) : InetAddress 객체 배열을 반환
InetAddress[] naver=InetAddress.getAllByName("www.naver.com");
for(InetAddress address:naver) {
System.out.println("IP Address = "+address.getHostAddress());
}}}
서버(Server) : 외부의 컴퓨터(클라이언트)가 접속할 수 있는 환경과 서비스를 제공하기 위한 컴퓨터
ServerSocket : 네트워크에서 서버 프로그램을 만들기 위해 사용하는 클래스
ServerSocket.close() : ServerSocket 객체를 제거하는 메소드
클라이언트(Client) : 서버에 접속하여 서비스를 제공받을 수 있는 컴퓨터 (서버 이용자)
cmd에서 netstat -na : 네트워크에서 사용중인지 확인 가능
public class ServerSocketApp {
public static void main(String[] args) {
for(int i=2000;i<=9000;i+=1000) {
try {
ServerSocket serverSocket=new ServerSocket(i);
//포트번호i 전달받아 객체 생성
System.out.println(i+"번 포트는 프로그램에서 사용 가능.");
serverSocket.close();
} catch (IOException e) {
System.out.println("[에러]"+i+"번 포트는 이미 사용중."); }}}}
네트워크 프로그램 : 두 대 이상의 컴퓨터에서 값을 주고 받는 프로그램
NTP(Network Time Protocol) Server : 날짜와 시간을 제공하는 서버 컴퓨터
ServerSocket.toString() : ServerSocket 객체에 저장된 접속 관련 정보를 문자열로 반환하는 메소드
ServerSocket.accept() : 클라이언트의 접속을 기다리는 메소드
socket.getOutputStream() : Socket 객체의 출력스트림(OutputStream 객체)을 반환하는 메소드
Socket.getInetAddress() : 소켓으로 연결된 외부 컴퓨터의 네트워크 정보(InetAddress 객체)를 반환하는 메소드
tcp프로그램에서는 서버(accept메소드)가 먼저 샐행되어야 클라이언트가 접속 가능
accept() 메소드 실행시 서버 프로그램에 다수의 클라이언트 접속을 허용하도록 무한루프 사용
public class TimeServerApp {
public static void main(String[] args) {
ServerSocket ntpServer=null;
try {
//포트(2000)를 활성화 시켜 클라이언트가 접속할 수 있는 환경 제공
ntpServer=new ServerSocket(2000);//ServerSocket 객체 생성
System.out.println(ntpServer);//: 포트가 2000인 ServerSocket주소
System.out.println("[메세지]NTP Server Running...");
while(true) {
Socket socket=ntpServer.accept();//Socket 객체 생성
System.out.println("socket = "+socket);
OutputStream out=socket.getOutputStream();
//OutputStream객체를 전달받아 객체 전달이 가능한
//ObjectOutputStream객체로 출력스트림 확장
ObjectOutputStream stream=new ObjectOutputStream(out);
//시스템의 현재 날짜와 시간이 저장된 Date 객체 생성
Date now=new Date();
//출력스트림을 이용하여 Date 객체 전달(client에게 날짜와 시간 전송)
stream.writeObject(now);//출력스트림으로 객체 전달
new ObjectOutputStream(socket.getOutputStream()).writeObject(new Date());
//로그 처리 - 기록
System.out.println("[정보]클라이언트["+socket.getInetAddress()
.getHostAddress()+"]에게 날짜와 시간을 제공 하였습니다.");
//클라이언트와의 연결 해제
socket.close();
}
} catch (IOException e) {
System.out.println("[에러]서버 네트워크에 문제가 발생 하였습니다."); }}}
Socket : TCP 프로그램에서 다른 컴퓨터와 연결을 위한 정보를 저장하기 위한 클래스
Socket(String host, int port) : 호스트(IP Address)와 포트를 전달하여 서버 컴퓨터에 접속한 Socket 객체를 생성하는 생성자
Socket.toString() : Socket 객체에 저장된 접속 관련 정보(접속 호스트 및 포트와 로컬 호스트 및 포트)을 문자열로 반환하는 메소드
Socket.getInputStream() : Socket 객체의 입력스트림(InputStream 객체)을 반환하는 메소드
Socket.close() : Socket 객체를 제거하는 메소드 - 접속해제
public class TimeClientApp {
public static void main(String[] args) throws ClassNotFoundException {
try {
Socket socket=new Socket("192.168.13.8", 2000);
//IP주소와 port가 정해진 socket 객체(서버) 생성
System.out.println("socket = "+socket);
InputStream in=socket.getInputStream();
//InputStream 객체를 전달받아 객체를 얻어올 수 있는
//ObjectInputStream 객체로 입력스트림 확장
ObjectInputStream stream=new ObjectInputStream(in);
//입력스트림에서 Date 객체를 얻어와 저장
Date date=(Date)stream.readObject();
//Date 객체에 저장된 날짜와 시간을 원하는 형식의 문자열로 변환하여 출력
System.out.println("서버에서 제공한 날짜와 시간 = "+new
SimpleDateFormat("yyyy년 MM월 dd일 E요일 HH시 mm분 dd일").format(date));
//Socket.close() : Socket 객체를 제거하는 메소드 - 접속해제
socket.close();
} catch (UnknownHostException e) {
System.out.println("[에러]서버 컴퓨터를 찾을 수 없습니다.");
} catch (IOException e) {
System.out.println("[에러]서버에 접속할 수 없습니다."); }}}
public class EchoServerApp {
public static void main(String[] args) {
ServerSocket echoServer=null;
try {
echoServer=new ServerSocket(3000);
System.out.println("[메세제]Echo Server Running...");
while(true) {
Socket socket=echoServer.accept();
//Socket 객체의 입력스트림을 반환받아 대량의 문자데이타를
//읽을 수 있는 입력스트림으로 확장
BufferedReader in=
new BufferedReader(new InputStreamReader(socket.getInputStream()));
//클라이언트에서 보내온 메세지를 입력스트림을 이용하여 얻어와 출력
// → 클라이언트에서 메세지를 보내기 전까지 스레드 일시 중지
System.out.println("["+socket.getInetAddress().getHostAddress()
+"]님이 보내온 메세지 = "+in.readLine());
socket.close();
}
} catch (IOException e) {
System.out.println("[에러]서버 네트워크에 문제가 발생 하였습니다."); }}}
PrintWriter.println(Object o) : 모든 형식의 값을 문자열로 처리하여 출력스트림으로 전달하는 메소드
키보드로 메세지를 입력받아 접속 서버에 전달하는 클라이언트 프로그램
public class EchoClientApp {
public static void main(String[] args) throws IOException {
//대량의 문자데이타를 입력받을 수 있도록 키보드 입력스트림 확장
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
System.out.print("전달 메세지 입력 >> ");
String message=in.readLine();
try {
//Socket 객체 생성 - 서버 접속
Socket socket=new Socket("192.168.13.8", 3000);
//소켓의 출력스트림을 반환받아 대량의 문자데이타를
//전달할 수 있는 출력스트림으로 확장
BufferedWriter out=
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//출력스트림을 이용하여 서버에 문자열(메세지) 전달
//문자데이타를 출력버퍼에 저장, 일정크기가 되면 출력스트림으로 전달
out.write(message);
//출력버퍼에 존재하는 문자데이타를 출력스트림으로 전달
out.flush();
//소켓의 출력스트림을 반환받아 모든 형식의 값을 전달할 수 있는 출력스트림으로 확장
PrintWriter out=new PrintWriter(socket.getOutputStream());
out.println(message);
out.flush();
//접속 해제
socket.close();
} catch (IOException e) {
System.out.println("[에러]서버에 접속할 수 없습니다."); }}}
DatagramSocket 클래스 : 다른 컴퓨터에 연결하기 위한 정보를 저장한 클래스
String.getBytes() : String 객체에 저장된 문자열을 byte 배열(원시데이타의 모임)로 변환하여 반환하는 메소드
DatagramPacket 클래스 : 연결 컴퓨터에게 보낼 패킷정보를 저장하기 위한 클래스
DatagramPacket(byte[] buf, int length, InetAddress address, int port) : DatagramPacket 객체를 생성하기 위한 생성자
DatagramSocket.send(DatagramPacket packet) : 패킷을 전달하는 메소드
DatagramSocket.close() : DatagramSocket 객체를 제거하는 메소드
DatagramSocket.receive(DatagramPacket packet) : 연결 컴퓨터에서 보내온 패킷을 얻어와 저장하는 메소드
public class MessageSendApp {
public static void main(String[] args) throws IOException {
//대량의 문자데이타를 입력받을 수 있는 키보드 입력스트림으로 확장
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
System.out.print("전달 메세지 입력 >> ");
String message=in.readLine();
DatagramSocket socket=new DatagramSocket();
//연결될 컴퓨터의 네트워크 정보를 저장한 InetAddress 객체 생성
InetAddress address=InetAddress.getByName("192.168.13.8");
byte[] data=message.getBytes(); //전달값을 원시데이타로 변환
DatagramPacket packet=new DatagramPacket(data, data.length, address, 4000);
socket.send(packet);//패킷을 전달하는 메소드
socket.close(); //DatagramSocket 객체를 제거
System.out.println("[결과]연결 컴퓨터에게 메세지를 보냈습니다."); }}
public class MessageReceiveApp {
public static void main(String[] args) throws IOException {
//DatagramSocket 객체 생성
// → 포트를 활성화하여 다른 컴퓨터에서 보내온 패킷을 받을 수 있는 환경 제공
DatagramSocket socket=new DatagramSocket(4000);
//전달받은 패킷에 저장된 값(메세지)를 저장하기 위한 byte 배열 선언
byte[] data=new byte[1024];
//연결 컴퓨터에서 보내온 패킷을 저장하기 위한 DatagramPacket 객체 생성
// → DatagramPacket(byte[] buf, int length) 생성자 이용
DatagramPacket packet=new DatagramPacket(data, data.length);
System.out.println("메세지 수신중...");
//DatagramSocket.receive(DatagramPacket packet) : 연결 컴퓨터에서 보내온 패킷을
//얻어와 저장하는 메소드 - 패킷을 받기 전까지 스레드 일시 중지
socket.receive(packet);
//byte 배열에 저장된 원시데이타를 문자열로 변환하여 저장
String message=new String(data);
System.out.println("[결과]메세지 = "+message);
socket.close(); }}
public class ChatServerApp {
//접속된 모든 클라이언트의 소켓정보를 저장하기 위한 콜렉션 필드
private List<SocketThread> clientList=null;
public ChatServerApp() {
ServerSocket chatServer=null;
try {
chatServer=new ServerSocket(5000);
System.out.println("[메세지]채팅 서버 동작 중...");
clientList=new ArrayList<SocketThread>();
while(true) {
try {
//클라이언트가 접속되면 클라이언트와 연결된 Socket 객체를 반환받아 저장
Socket client=chatServer.accept();
System.out.println("[접속로그]"+client.getInetAddress().getHostAddress()
+"의 컴퓨터에서 접속 하였습니다.");
//Thread 클래스를 상속받은 자식클래스로 객체 생성 - Thread 객체 생성
SocketThread socketThread=new SocketThread(client);
//콜렉션 필드에 저장된 List 객체에 요소(SocketThread 객체)를 추가하여 저장
clientList.add(socketThread);
//Thread 객체로 새로운 스레드를 생성하여 run() 메소드의 명령 실행
socketThread.start();
} catch (IOException e) {
System.out.println("클라이언트의 접속 관련 문제가 발생 되었습니다.");
}
}
} catch (IOException e) {
System.out.println("[에러로그]서버가 정상적으로 동작되지 않습니다.");
}
}
public static void main(String[] args) {
new ChatServerApp();
}
//현재 서버에 접속된 모든 클라이언트에게 메세지를 전달하는 메소드
public void sendMessage(String message) {
//List 객체에 저장된 요소(SocketThread 객체)를 하나씩 제공받아 반복 처리
for(SocketThread client:clientList) {
//SocketThread 객체의 출력스트림을 이용하여 클라이언트에게 메세지 전달
client.out.println(message);
}
}
//클라이언트와 연결된 소켓을 이용하여 입출력 기능을 제공하기 위한 클래스
// → 독립적인 입력 또는 출력 기능을 제공하기 위해 새로운 스레드를 생성하여 실행되도록 설정
public class SocketThread extends Thread {
//클라이언트의 소켓과 연결된 Socket 객체를 저장하기 위한 필드
private Socket socket;
//클라이언트에서 보내온 메세지를 읽기 위한 입력스트림을 저장하기 위한 필드
private BufferedReader in;
//클라이언트로 메세지 보내기 위한 출력스트림을 저장하기 위한 필드
private PrintWriter out;
public SocketThread(Socket socket) {
this.socket = socket;
}
//새로운 스레드가 실행하기 위한 명령 작성
// → 클라이언트의 메세지를 전달받아 모든 접속 클라이언트에게 전달하는 명령 실행
@Override
public void run() {
String aliasName="";//클라이언트의 대화명을 저장하기 위한 변수 선언
try {
//클라이언트와 연결된 소켓의 입력스트림을 반환받아 대량의 문자데이타를
//읽을 수 있는 입력스트림으로 확장
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//클라이언트와 연결된 소켓의 출력스트림을 반환받아 모든 형식의 값을 문자열로
//전달할 수 있는 출력스트림으로 확장
//out=new PrintWriter(socket.getOutputStream());//출력버퍼 사용
//PrintWriter(OutputStream out, boolean autoFlush) : autoFlush 매개변수에
//[true]를 전달할 경우 출력버퍼를 사용하지 않고 출력스트림에 값을 직접 전달
out=new PrintWriter(socket.getOutputStream(), true);
//클라이언트에서 보내온 대화명을 얻어와 변수에 저장
// → 클라이언트에서 대화명을 입력받아 전달할 때까지 스레드 일시 중지
aliasName=in.readLine();
//현재 접속된 모든 클라이언트에게 입장 메세지를 전달
sendMessage("["+aliasName+"]님이 입장 하였습니다.");
//클라이언트에서 보내온 메세지를 전달받아 현재 접속된 모든 클라이언트에게 전달
// → 클라이언트가 접속을 종료하기 전까지 반복 처리
// → 클라이언트가 접속을 종료하면 클라이언트와 연결된 소켓의 입력스트림과
//출력스트림에 제거되어 IOException 발생
while(true) {
sendMessage("["+aliasName+"]"+in.readLine());
}
} catch (IOException e) {
//클라이언트가 접속을 종료한 경우 실행될 명령 작성
//콜렉션 필드에 저장된 List 객체에서 접속 종료된 client의 소켓정보(SocketThread)삭제
// → 현재 접속중인 모든 클라이언트에게 퇴장 메세지 전달
clientList.remove(this);//this 키워드로 현재 사용중인 SocketThread 객체 표현
sendMessage("["+aliasName+"]님이 퇴장 하였습니다.");
System.out.println("[해제로그]"+socket.getInetAddress().getHostAddress()
+"의 컴퓨터에서 접속을 종료 하였습니다."); }}}}
public class ChatClientApp extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JTextArea area;//출력 컴퍼넌트
private JTextField field;//입력 컴퍼넌트
//서버의 소켓과 연결된 소켓정보를 저장하기 위한 필드
private Socket socket;
//서버에서 보내온 메세지를 읽기 위한 입력스트림을 저장하기 위한 필드
private BufferedReader in;
//서버에서 메세지를 보내기 위한 출력스트림을 저장하기 위한 필드
private PrintWriter out;
//대화명을 저장하기 위한 필드
private String aliasName;
public ChatClientApp(String title) {
super(title);
area=new JTextArea();
field=new JTextField();
JScrollPane pane=new JScrollPane(area);
getContentPane().add(pane, BorderLayout.CENTER);
getContentPane().add(field, BorderLayout.SOUTH);
area.setFont(new Font("굴림체", Font.BOLD, 20));
field.setFont(new Font("굴림체", Font.BOLD, 20));
area.setFocusable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(700, 200, 400, 500);
setVisible(true);
//JTextField 컴퍼넌트에서 이벤트가 발생될 경우 실행될 이벤트 처리 객체 등록
// → 클라이언트가 메세지를 입력한 경우 실행될 명령을 이벤트 처리 메소드에 작성
field.addActionListener(this);
try {
//Socket 객체 생성 - 채팅 서버에 접속
socket=new Socket("192.168.13.31", 5000);
//서버와 연결된 소켓의 입력스트림을 반환받아 대량의 문자데이타를 읽을 수
//있는 입력스트림으로 확장
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//서버와 연결된 소켓의 출력스트림을 반환받아 모든 형식의 값을 문자열로 전달할 수
//있는 출력스트림으로 확장
out=new PrintWriter(socket.getOutputStream(), true);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "서버에 접속할 수 없습니다.",
"접속오류", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
//대화명을 입력받아 필드에 저장
// → 정상적인 대화명이 입력되도록 무한루프 이용
while(true) {
//JOptionPane.showInputDialog(Component parent, String message,
//String title, int messageType)
// → 입력 다이얼로그를 보여주는 메소드 - 입력값을 문자열로 반환
aliasName=JOptionPane.showInputDialog(this,"대화명을 입력해 주세요.",
"대화명 입력", JOptionPane.QUESTION_MESSAGE);
String regEx="^[가-힣]{2,6}$";
//정상적인 대화명을 입력한 경우 반복문 종료
if(Pattern.matches(regEx, aliasName)) break;
JOptionPane.showMessageDialog(this, "정상적인 대화명을 입력해 주세요.",
"입력오류", JOptionPane.ERROR_MESSAGE);
}
//서버에 대화명 전달
out.println(aliasName);
//서버에서 보내온 메세지를 전달받아 JTextArea 컴퍼넌트에 추가하여 출력 - 무한루프
while(true) {
try {
area.append(in.readLine()+"\n");
//JTextArea 컴퍼넌트의 스크롤을 맨 아래로 이동 처리
area.setCaretPosition(area.getText().length());
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "서버와 연결이 끊어졌습니다.",
"접속오류", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
}
public static void main(String[] args) {
new ChatClientApp("자바채팅");
}
//이벤트 처리 메소드에서는 JTextField 컴퍼넌트의 입력값(메세지)을 반환받아
//서버에 전달하는 명령 작성
@Override
public void actionPerformed(ActionEvent e) {
//JTextField 컴퍼넌트의 입력값을 반환받아 저장
String message=field.getText();
if(!message.equals("")) {//입력메세지가 존재하는 경우
out.println(message);//서버에 메세지 전달
field.setText("");//JTextField 컴퍼넌트 초기화 }}}